home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / graphics / gnuplot / graph3d.c < prev    next >
C/C++ Source or Header  |  1993-09-15  |  82KB  |  2,894 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: graph3d.c%v 3.50.1.9 1993/08/05 05:38:59 woo Exp $";
  3. #endif
  4.  
  5.  
  6. /* GNUPLOT - graph3d.c */
  7. /*
  8.  * Copyright (C) 1986 - 1993   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted, 
  12.  * provided that the above copyright notice appear in all copies and 
  13.  * that both that copyright notice and this permission notice appear 
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the modified code.  Modifications are to be distributed 
  18.  * as patches to released version.
  19.  *
  20.  * This software is provided "as is" without express or implied warranty.
  21.  *
  22.  *
  23.  * AUTHORS
  24.  *
  25.  *   Original Software:
  26.  *       Gershon Elber and many others.
  27.  *
  28.  * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
  29.  * Added user-specified bases for log scaling.
  30.  *
  31.  * There is a mailing list for gnuplot users. Note, however, that the
  32.  * newsgroup 
  33.  *    comp.graphics.gnuplot 
  34.  * is identical to the mailing list (they
  35.  * both carry the same set of messages). We prefer that you read the
  36.  * messages through that newsgroup, to subscribing to the mailing list.
  37.  * (If you can read that newsgroup, and are already on the mailing list,
  38.  * please send a message info-gnuplot-request@dartmouth.edu, asking to be
  39.  * removed from the mailing list.)
  40.  *
  41.  * The address for mailing to list members is
  42.  *       info-gnuplot@dartmouth.edu
  43.  * and for mailing administrative requests is 
  44.  *       info-gnuplot-request@dartmouth.edu
  45.  * The mailing list for bug reports is 
  46.  *       bug-gnuplot@dartmouth.edu
  47.  * The list of those interested in beta-test versions is
  48.  *       info-gnuplot-beta@dartmouth.edu
  49.  */
  50.  
  51. #include <stdio.h>
  52. #include <math.h>
  53. #include <assert.h>
  54. #if !defined(u3b2)
  55. #include <time.h>
  56. #endif
  57. #if !defined(sequent) && !defined(apollo) && !defined(alliant)
  58. #include <limits.h>
  59. #endif
  60. #include "plot.h"
  61. #include "setshow.h"
  62.  
  63. #if defined(DJGPP)||defined(sun386)
  64. #define time_t unsigned long
  65. #endif
  66.  
  67. #if defined(apollo) || defined(sequent) || defined(u3b2) || defined(alliant) || defined(sun386)
  68. #include <sys/types.h> /* typedef long time_t; */
  69. #endif
  70.  
  71. int suppressMove = 0;  /* for preventing moveto while drawing contours */
  72. #ifndef AMIGA_SC_6_1
  73. extern char *strcpy(),*strncpy(),*strcat(),*ctime(),*tdate;
  74. #else /* AMIGA_SC_6_1 */
  75. extern char *tdate;
  76. #endif /* AMIGA_SC_6_1 */
  77. #ifdef AMIGA_AC_5
  78. extern time_t dated;
  79. #else
  80. extern time_t dated; /* ,time(); */
  81. #include <time.h>
  82. #endif
  83.  
  84. #ifdef __TURBOC__
  85. #include <stdlib.h>        /* for qsort */
  86. #endif
  87.  
  88. /*
  89.  * hidden_line_type_above, hidden_line_type_below - controls type of lines
  90.  *   for above and below parts of the surface.
  91.  * hidden_no_update - if TRUE lines will be hidden line removed but they
  92.  *   are not assumed to be part of the surface (i.e. grid) and therefore
  93.  *   do not influence the hidings.
  94.  * hidden_active - TRUE if hidden lines are to be removed.
  95.  */
  96. static int hidden_active = FALSE;
  97.  
  98. /* LITE defines a restricted memory version for MS-DOS */
  99.  
  100. #ifndef LITE
  101.  
  102. static int hidden_line_type_above, hidden_line_type_below, hidden_no_update;
  103.  
  104. /* We divvy up the figure into the component boxes that make it up, and then
  105.    sort them by the z-value (which is really just an average value).  */
  106. struct pnts{
  107.   int x,y,z;
  108.   int flag;
  109.   long int style_used;    /* acw test */
  110.   int nplot;
  111. };
  112. static int * boxlist;
  113. static struct pnts * nodes;
  114. /* These variables are used to keep track of the range of x values used in the
  115. line drawing routine.  */
  116. static long int xmin_hl,xmax_hl;
  117. /* These arrays are used to keep track of the minimum and maximum y values used
  118.    for each X value.  These are only used for drawing the individual boxes that
  119.    make up the 3d figure.  After each box is drawn, the information is copied
  120.    to the bitmap. */
  121. static short int *ymin_hl, *ymax_hl;
  122. /*
  123.  * These numbers are chosen as dividers into the bitmap.
  124.  */
  125. static short int xfact, yfact;
  126. #define XREDUCE(X) ((X)/xfact)
  127. #define YREDUCE(Y) ((Y)/yfact)
  128. /* Bitmap of the screen.  The array for each x value is malloc-ed as needed */
  129. static short int **pnt;
  130. #define IFSET(X,Y) (pnt[X] == 0 ? 0 : (((pnt[X])[(Y)>>4] >> ((Y) & 0xf)) & 0x01))
  131. static plot3d_hidden();
  132.  
  133. #endif /* LITE */
  134.  
  135.  
  136. static plot3d_impulses();
  137. static plot3d_lines();
  138. static plot3d_points();
  139. static plot3d_dots();
  140. static cntr3d_impulses();
  141. static cntr3d_lines();
  142. static cntr3d_points();
  143. static cntr3d_dots();
  144. static update_extrema_pts();
  145. static draw_parametric_grid();
  146. static draw_non_param_grid();
  147. static draw_bottom_grid();
  148. static draw_3dxtics();
  149. static draw_3dytics();
  150. static draw_3dztics();
  151. static draw_series_3dxtics();
  152. static draw_series_3dytics();
  153. static draw_series_3dztics();
  154. static draw_set_3dxtics();
  155. static draw_set_3dytics();
  156. static draw_set_3dztics();
  157. static xtick();
  158. static ytick();
  159. static ztick();
  160. static setlinestyle();
  161. #ifdef __PUREC__
  162. /* a little problem with the 16bit int size of PureC. this completely broke
  163.    the hidded3d feature. doesn't really fix it, but I'm working at it.  (AL) */
  164. static int clip_point(int x, int y);
  165. static void clip_put_text(int x, int y, char *str);
  166. #endif
  167.  
  168. #ifndef max        /* Lattice C has max() in math.h, but shouldn't! */
  169. #define max(a,b) ((a > b) ? a : b)
  170. #endif
  171.  
  172. #ifndef min
  173. #define min(a,b) ((a < b) ? a : b)
  174. #endif
  175.  
  176. #define inrange(z,min,max) ((min<max) ? ((z>=min)&&(z<=max)) : ((z>=max)&&(z<=min)) )
  177.  
  178. #define apx_eq(x,y) (fabs(x-y) < 0.001)
  179. #ifndef abs
  180. #define abs(x) ((x) >= 0 ? (x) : -(x))
  181. #endif
  182. #define sqr(x) ((x) * (x))
  183.  
  184. /* Define the boundary of the plot
  185.  * These are computed at each call to do_plot, and are constant over
  186.  * the period of one do_plot. They actually only change when the term
  187.  * type changes and when the 'set size' factors change. 
  188.  */
  189. static int xleft, xright, ybot, ytop, xmiddle, ymiddle, xscaler, yscaler;
  190.  
  191. /* Boundary and scale factors, in user coordinates */
  192. /* x_min3d, x_max3d, y_min3d, y_max3d, z_min3d, z_max3d are local to this
  193.  * file and are not the same as variables of the same names in other files
  194.  */
  195. static double x_min3d, x_max3d, y_min3d, y_max3d, z_min3d, z_max3d;
  196. static double xscale3d, yscale3d, zscale3d;
  197. static double real_z_min3d, real_z_max3d;
  198. static double min_sy_ox,min_sy_oy; /* obj. coords. for xy tics placement. */
  199. static double min_sx_ox,min_sx_oy; /* obj. coords. for z tics placement. */
  200.  
  201. typedef double transform_matrix[4][4];
  202. static transform_matrix trans_mat;
  203.  
  204. /* (DFK) Watch for cancellation error near zero on axes labels */
  205. #define SIGNIF (0.01)        /* less than one hundredth of a tic mark */
  206. #define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
  207. #define NearlyEqual(x,y,tic) (fabs((x)-(y)) < ((tic) * SIGNIF))
  208.  
  209. /* And the functions to map from user to terminal coordinates */
  210. #define map_x(x) (int)(x+0.5) /* maps floating point x to screen */ 
  211. #define map_y(y) (int)(y+0.5)    /* same for y */
  212.  
  213. /* And the functions to map from user 3D space into normalized -1..1 */
  214. #define map_x3d(x) ((x-x_min3d)*xscale3d-1.0)
  215. #define map_y3d(y) ((y-y_min3d)*yscale3d-1.0)
  216. #define map_z3d(z) ((z-z_min3d)*zscale3d-1.0)
  217.  
  218. static mat_unit(mat)
  219. transform_matrix mat;
  220. {
  221.     int i, j;
  222.  
  223.     for (i = 0; i < 4; i++) for (j = 0; j < 4; j++)
  224.     if (i == j)
  225.         mat[i][j] = 1.0;
  226.     else
  227.         mat[i][j] = 0.0;
  228. }
  229.  
  230. static mat_trans(tx, ty, tz, mat)
  231. double tx, ty, tz;
  232. transform_matrix mat;
  233. {
  234.      mat_unit(mat);                                 /* Make it unit matrix. */
  235.      mat[3][0] = tx;
  236.      mat[3][1] = ty;
  237.      mat[3][2] = tz;
  238. }
  239.  
  240. static mat_scale(sx, sy, sz, mat)
  241. double sx, sy, sz;
  242. transform_matrix mat;
  243. {
  244.      mat_unit(mat);                                 /* Make it unit matrix. */
  245.      mat[0][0] = sx;
  246.      mat[1][1] = sy;
  247.      mat[2][2] = sz;
  248. }
  249.  
  250. static mat_rot_x(teta, mat)
  251. double teta;
  252. transform_matrix mat;
  253. {
  254.     double cos_teta, sin_teta;
  255.  
  256.     teta *= Pi / 180.0;
  257.     cos_teta = cos(teta);
  258.     sin_teta = sin(teta);
  259.  
  260.     mat_unit(mat);                                  /* Make it unit matrix. */
  261.     mat[1][1] = cos_teta;
  262.     mat[1][2] = -sin_teta;
  263.     mat[2][1] = sin_teta;
  264.     mat[2][2] = cos_teta;
  265. }
  266.  
  267. static mat_rot_y(teta, mat)
  268. double teta;
  269. transform_matrix mat;
  270. {
  271.     double cos_teta, sin_teta;
  272.  
  273.     teta *= Pi / 180.0;
  274.     cos_teta = cos(teta);
  275.     sin_teta = sin(teta);
  276.  
  277.     mat_unit(mat);                                  /* Make it unit matrix. */
  278.     mat[0][0] = cos_teta;
  279.     mat[0][2] = -sin_teta;
  280.     mat[2][0] = sin_teta;
  281.     mat[2][2] = cos_teta;
  282. }
  283.  
  284. static mat_rot_z(teta, mat)
  285. double teta;
  286. transform_matrix mat;
  287. {
  288.     double cos_teta, sin_teta;
  289.  
  290.     teta *= Pi / 180.0;
  291.     cos_teta = cos(teta);
  292.     sin_teta = sin(teta);
  293.  
  294.     mat_unit(mat);                                  /* Make it unit matrix. */
  295.     mat[0][0] = cos_teta;
  296.     mat[0][1] = -sin_teta;
  297.     mat[1][0] = sin_teta;
  298.     mat[1][1] = cos_teta;
  299. }
  300.  
  301. /* Multiply two transform_matrix. Result can be one of two operands. */
  302. void mat_mult(mat_res, mat1, mat2)
  303. transform_matrix mat_res, mat1, mat2;
  304. {
  305.     int i, j, k;
  306.     transform_matrix mat_res_temp;
  307.  
  308.     for (i = 0; i < 4; i++) for (j = 0; j < 4; j++) {
  309.         mat_res_temp[i][j] = 0;
  310.         for (k = 0; k < 4; k++) mat_res_temp[i][j] += mat1[i][k] * mat2[k][j];
  311.     }
  312.     for (i = 0; i < 4; i++) for (j = 0; j < 4; j++)
  313.     mat_res[i][j] = mat_res_temp[i][j];
  314. }
  315.  
  316. /* And the functions to map from user 3D space to terminal coordinates */
  317. static int map3d_xy(x, y, z, xt, yt)
  318. double x, y, z;
  319. int *xt, *yt;
  320. {
  321.     int i,j;
  322.     double v[4], res[4],             /* Homogeneous coords. vectors. */
  323.     w = trans_mat[3][3];
  324.  
  325.     v[0] = map_x3d(x); /* Normalize object space to -1..1 */
  326.     v[1] = map_y3d(y);
  327.     v[2] = map_z3d(z);
  328.     v[3] = 1.0;
  329.  
  330.     for (i = 0; i < 2; i++) {                 /* Dont use the third axes (z). */
  331.         res[i] = trans_mat[3][i];     /* Initiate it with the weight factor. */
  332.         for (j = 0; j < 3; j++) res[i] += v[j] * trans_mat[j][i];
  333.     }
  334.  
  335.     for (i = 0; i < 3; i++) w += v[i] * trans_mat[i][3];
  336.     if (w == 0) w = 1e-5;
  337.  
  338.     *xt = ((int) (res[0] * xscaler / w)) + xmiddle;
  339.     *yt = ((int) (res[1] * yscaler / w)) + ymiddle;
  340. }
  341.  
  342. /* And the functions to map from user 3D space to terminal z coordinate */
  343. static int map3d_z(x, y, z)
  344. double x, y, z;
  345. {
  346.     int i, zt;
  347.     double v[4], res,                 /* Homogeneous coords. vectors. */
  348.     w = trans_mat[3][3];
  349.  
  350.     v[0] = map_x3d(x); /* Normalize object space to -1..1 */
  351.     v[1] = map_y3d(y);
  352.     v[2] = map_z3d(z);
  353.     v[3] = 1.0;
  354.  
  355.     res = trans_mat[3][2];               /* Initiate it with the weight factor. */
  356.     for (i = 0; i < 3; i++) res += v[i] * trans_mat[i][2];
  357.     if(w==0) w= 1e-5;
  358.     for (i = 0; i < 3; i++) w += v[i] * trans_mat[i][3];
  359.     zt = ((int) (res * 16384 / w));
  360.     return  zt;
  361. }
  362.  
  363. /* Initialize the line style using the current device and set hidden styles  */
  364. /* to it as well if hidden line removal is enabled.                 */
  365. static setlinestyle(style)
  366. int style;
  367. {
  368.     register struct termentry *t = &term_tbl[term];
  369.  
  370.     (*t->linetype)(style);
  371.  
  372. #ifndef LITE
  373.     if (hidden3d) {
  374.     hidden_line_type_above = style;
  375.     hidden_line_type_below = style;
  376.     }
  377. #endif  /* LITE */
  378. }
  379.  
  380. #ifndef LITE
  381. /* Initialize the necessary steps for hidden line removal. */
  382. static void init_hidden_line_removal()
  383. {
  384.   int i;
  385.   /*  We want to keep the bitmap size less than 2048x2048, so we choose
  386.    *  integer dividers for the x and y coordinates to keep the x and y
  387.    *  ranges less than 2048.  In practice, the x and y sizes for the bitmap
  388.    *  will be somewhere between 1024 and 2048, except in cases where the
  389.    *  coordinates ranges for the device are already less than 1024.
  390.    *  We do this mainly to control the size of the bitmap, but it also
  391.    *  speeds up the computation.  We maintain separate dividers for
  392.    *  x and y.
  393.    */
  394.   xfact = (xright-xleft)/1024;
  395.   yfact = (ytop-ybot)/1024;
  396.   if(xfact == 0) xfact=1;
  397.   if(yfact == 0) yfact=1;
  398.   if(pnt == 0){
  399.     i = sizeof(short int*)*(XREDUCE(xright) - XREDUCE(xleft) + 1);
  400.     pnt = (short int **) alloc((unsigned long)i, "hidden");
  401.     bzero(pnt,i);
  402.   };
  403.   ymin_hl = (short int *) alloc((unsigned long)sizeof(short int)*
  404.                 (XREDUCE(xright) - XREDUCE(xleft) + 1), "hidden");
  405.   ymax_hl = (short int *) alloc((unsigned long)sizeof(short int)*
  406.                 (XREDUCE(xright) - XREDUCE(xleft) + 1), "hidden");
  407. }
  408.  
  409. /* Reset the hidden line data to a fresh start.                     */
  410. static void reset_hidden_line_removal()
  411. {
  412.     int i;
  413.     if(pnt){
  414.       for(i=0;i<=XREDUCE(xright)-XREDUCE(xleft);i++) {
  415.     if(pnt[i])
  416.       { free(pnt[i]); pnt[i] = 0;};
  417.       };
  418.     };
  419. }
  420.  
  421. /* Terminates the hidden line removal process. Free any memory allocated by  */
  422. /* init_hidden_line_removal above.                         */
  423. static void term_hidden_line_removal()
  424. {
  425.      if(pnt){
  426.        int j;
  427.        for(j=0;j<=XREDUCE(xright)-XREDUCE(xleft);j++) {
  428.      if(pnt[j])
  429.        { free(pnt[j]); pnt[j] = 0;};
  430.        };
  431.        free(pnt);
  432.        pnt = 0;
  433.      };
  434.    free(ymin_hl);
  435.    free(ymax_hl);
  436. }
  437. #endif /* not LITE */
  438.  
  439. /* Test a single point to be within the xleft,xright,ybot,ytop bbox.
  440.  * Sets the returned integers 4 l.s.b. as follows:
  441.  * bit 0 if to the left of xleft.
  442.  * bit 1 if to the right of xright.
  443.  * bit 2 if above of ytop.
  444.  * bit 3 if below of ybot.
  445.  * 0 is returned if inside.
  446.  */
  447. static int clip_point(x, y)
  448. int x, y;
  449. {
  450.     int ret_val = 0;
  451.  
  452.     if (x < xleft) ret_val |= 0x01;
  453.     if (x > xright) ret_val |= 0x02;
  454.     if (y < ybot) ret_val |= 0x04;
  455.     if (y > ytop) ret_val |= 0x08;
  456.  
  457.     return ret_val;
  458. }
  459.  
  460.  
  461. /* Clip the given line to drawing coords defined as xleft,xright,ybot,ytop.
  462.  *   This routine uses the cohen & sutherland bit mapping for fast clipping -
  463.  * see "Principles of Interactive Computer Graphics" Newman & Sproull page 65.
  464.  */
  465. static void draw_clip_line(x1, y1, x2, y2)
  466. int x1, y1, x2, y2;
  467. {
  468.     int x, y, dx, dy, x_intr[2], y_intr[2], count, pos1, pos2;
  469.     register struct termentry *t = &term_tbl[term];
  470.  
  471.     pos1 = clip_point(x1, y1);
  472.     pos2 = clip_point(x2, y2);
  473.     if (pos1 || pos2) {
  474.     if (pos1 & pos2) return;          /* segment is totally out. */
  475.  
  476.     /* Here part of the segment MAY be inside. test the intersection
  477.      * of this segment with the 4 boundaries for hopefully 2 intersections
  478.      * in. If non found segment is totaly out.
  479.      */
  480.     count = 0;
  481.     dx = x2 - x1;
  482.     dy = y2 - y1;
  483.  
  484.     /* Find intersections with the x parallel bbox lines: */
  485.     if (dy != 0) {
  486.         x = (ybot - y2) * dx / dy + x2;        /* Test for ybot boundary. */
  487.         if (x >= xleft && x <= xright) {
  488.         x_intr[count] = x;
  489.         y_intr[count++] = ybot;
  490.         }
  491.         x = (ytop - y2) * dx / dy + x2;        /* Test for ytop boundary. */
  492.         if (x >= xleft && x <= xright) {
  493.         x_intr[count] = x;
  494.         y_intr[count++] = ytop;
  495.         }
  496.     }
  497.  
  498.     /* Find intersections with the y parallel bbox lines: */
  499.     if (dx != 0) {
  500.         y = (xleft - x2) * dy / dx + y2;      /* Test for xleft boundary. */
  501.         if (y >= ybot && y <= ytop) {
  502.         x_intr[count] = xleft;
  503.         y_intr[count++] = y;
  504.         }
  505.         y = (xright - x2) * dy / dx + y2;    /* Test for xright boundary. */
  506.         if (y >= ybot && y <= ytop) {
  507.         x_intr[count] = xright;
  508.         y_intr[count++] = y;
  509.         }
  510.     }
  511.  
  512.     if (count == 2) {
  513.         int x_max, x_min, y_max, y_min;
  514.  
  515.         x_min = min(x1, x2);
  516.         x_max = max(x1, x2);
  517.         y_min = min(y1, y2);
  518.         y_max = max(y1, y2);
  519.  
  520.         if (pos1 && pos2) {               /* Both were out - update both */
  521.         x1 = x_intr[0];
  522.         y1 = y_intr[0];
  523.         x2 = x_intr[1];
  524.         y2 = y_intr[1];
  525.         }
  526.         else if (pos1) {           /* Only x1/y1 was out - update only it */
  527.         if (dx * (x2 - x_intr[0]) + dy * (y2 - y_intr[0]) > 0) {
  528.             x1 = x_intr[0];
  529.             y1 = y_intr[0];
  530.         }
  531.         else {
  532.             x1 = x_intr[1];
  533.             y1 = y_intr[1];
  534.         }
  535.         }
  536.         else {                      /* Only x2/y2 was out - update only it */
  537.         if (dx * (x_intr[0] - x1) + dy * (y_intr[0] - x1) > 0) {
  538.             x2 = x_intr[0];
  539.             y2 = y_intr[0];
  540.         }
  541.         else {
  542.             x2 = x_intr[1];
  543.             y2 = y_intr[1];
  544.         }
  545.         }
  546.  
  547.         if (x1 < x_min || x1 > x_max ||
  548.         x2 < x_min || x2 > x_max ||
  549.         y1 < y_min || y1 > y_max ||
  550.         y2 < y_min || y2 > y_max) return;
  551.     }
  552.     else
  553.         return;
  554.     }
  555.  
  556. #ifndef LITE
  557.     if(hidden3d && draw_surface)
  558.       {
  559.     char flag;
  560.     register int xv, yv, errx, erry, err;
  561.     register int xvr, yvr;
  562.     int xve, yve;
  563.     register int dy, nstep, dyr;
  564.     int i;
  565.     if (x1 > x2){
  566.       xvr = x2;
  567.       yvr = y2;
  568.       xve = x1;
  569.       yve = y1;
  570.     } else {
  571.       xvr = x1;
  572.       yvr = y1;
  573.       xve = x2;
  574.       yve = y2;
  575.     };
  576.     errx = XREDUCE(xve) - XREDUCE(xvr);
  577.     erry = YREDUCE(yve) - YREDUCE(yvr);
  578.     dy = (erry > 0 ? 1 : -1);
  579.     dyr = dy*yfact;
  580.     switch (dy){
  581.     case 1:
  582.       nstep = errx + erry;
  583.       errx = -errx;
  584.       break;
  585.     case -1:
  586.       nstep = errx - erry;
  587.       errx = -errx;
  588.       erry = -erry;
  589.       break;
  590.     };
  591.     err = errx + erry;
  592.     errx <<= 1;
  593.     erry <<= 1;
  594.     xv = XREDUCE(xvr) - XREDUCE(xleft);
  595.     yv = YREDUCE(yvr) - YREDUCE(ybot);
  596.     (*t->move)(xvr,yvr);
  597.     if( !IFSET(xv,yv) ) flag = 0;
  598.     else flag = 1;
  599.     if(!hidden_no_update){ /* Check first point */
  600.       if (xv < xmin_hl) xmin_hl = xv;
  601.       if (xv > xmax_hl) xmax_hl = xv;
  602.       if (yv > ymax_hl[xv]) ymax_hl[xv] = yv;
  603.       if (yv < ymin_hl[xv]) ymin_hl[xv] = yv;
  604.     };
  605.     for (i=0;i<nstep;i++){
  606.       if (err < 0){
  607.         xv ++;
  608.         xvr += xfact;
  609.         err += erry;
  610.       } else {
  611.         yv += dy;
  612.         yvr += dyr;
  613.         err += errx;
  614.       };
  615.       if( !IFSET(xv,yv)){
  616.         if(flag != 0) {(*t->move)(xvr,yvr); flag = 0;};
  617.       } else {
  618.         if(flag == 0) {(*t->vector)(xvr,yvr); flag = 1;};
  619.       };
  620.       if(!hidden_no_update){
  621.         if (xv < xmin_hl) xmin_hl = xv;
  622.         if (xv > xmax_hl) xmax_hl = xv;
  623.         if (yv > ymax_hl[xv]) ymax_hl[xv] = yv;
  624.         if (yv < ymin_hl[xv]) ymin_hl[xv] = yv;
  625.       };
  626.     };
  627.     if (flag == 0) (*t->vector)(xve, yve);
  628.     return;
  629.       };
  630. #endif /* not LITE */
  631.     if(!suppressMove) (*t->move)(x1,y1);
  632.     (*t->vector)(x2,y2);
  633. }
  634.  
  635. /* Two routine to emulate move/vector sequence using line drawing routine. */
  636. static int move_pos_x, move_pos_y;
  637.  
  638. static void clip_move(x,y)
  639. int x,y;
  640. {
  641.     move_pos_x = x;
  642.     move_pos_y = y;
  643. }
  644.  
  645. static void clip_vector(x,y)
  646. int x,y;
  647. {
  648.     draw_clip_line(move_pos_x,move_pos_y, x, y);
  649.     move_pos_x = x;
  650.     move_pos_y = y;
  651. }
  652.  
  653. /* And text clipping routine. */
  654. static void clip_put_text(x, y, str)
  655. int x,y;
  656. char *str;
  657. {
  658.     register struct termentry *t = &term_tbl[term];
  659.  
  660.     if (clip_point(x, y)) return;
  661.  
  662.     (*t->put_text)(x,y,str);
  663. }
  664.  
  665. /* (DFK) For some reason, the Sun386i compiler screws up with the CheckLog 
  666.  * macro, so I write it as a function on that machine.
  667.  */
  668. #ifndef sun386
  669. /* (DFK) Use 10^x if logscale is in effect, else x */
  670. #define CheckLog(is_log, base_log, x) ((is_log) ? pow(base_log, (x)) : (x))
  671. #else
  672. static double
  673. CheckLog(is_log, base_log, x)
  674.      TBOOLEAN is_log;
  675.      double base_log;
  676.      double x;
  677. {
  678.   if (is_log)
  679.     return(pow(base_log, x));
  680.   else
  681.     return(x);
  682. }
  683. #endif /* sun386 */
  684.  
  685. static double
  686. LogScale(coord, is_log, log_base_log, what, axis)
  687.     double coord;            /* the value */
  688.     TBOOLEAN is_log;            /* is this axis in logscale? */
  689.     double log_base_log;        /* if so, the log of its base */
  690.     char *what;            /* what is the coord for? */
  691.     char *axis;            /* which axis is this for ("x" or "y")? */
  692. {
  693.     if (is_log) {
  694.        if (coord <= 0.0) {
  695.           char errbuf[100];        /* place to write error message */
  696.         (void) sprintf(errbuf,"%s has %s coord of %g; must be above 0 for log scale!",
  697.                 what, axis, coord);
  698.           (*term_tbl[term].text)();
  699.           (void) fflush(outfile);
  700.           int_error(errbuf, NO_CARET);
  701.        } else
  702.         return(log(coord)/log_base_log);
  703.     }
  704.     return(coord);
  705. }
  706.  
  707. /* borders of plotting area */
  708. /* computed once on every call to do_plot */
  709. static boundary3d(scaling)
  710.     TBOOLEAN scaling;        /* TRUE if terminal is doing the scaling */
  711. {
  712.     register struct termentry *t = &term_tbl[term];
  713.     /* luecken@udel.edu modifications
  714.        sizes the plot to take up more of available resolution */
  715.     xleft = (t->h_char)*2 + (t->h_tic);
  716.     xright = (scaling ? 1 : xsize) * (t->xmax) - (t->h_char)*2 - (t->h_tic);
  717.     ybot = (t->v_char)*5/2 + 1;
  718.     ytop = (scaling ? 1 : ysize) * (t->ymax) - (t->v_char)*5/2 - 1;
  719.     xmiddle = (xright + xleft) / 2;
  720.     ymiddle = (ytop + ybot) / 2;
  721.     xscaler = (xright - xleft) * 4 / 7;
  722.     yscaler = (ytop - ybot) * 4 / 7;
  723. }
  724.  
  725. static double dbl_raise(x,y)
  726. double x;
  727. int y;
  728. {
  729. register int i;
  730. double val;
  731.  
  732.     val = 1.0;
  733.     for (i=0; i < abs(y); i++)
  734.         val *= x;
  735.     if (y < 0 ) return (1.0/val);
  736.     return(val);
  737. }
  738.  
  739.  
  740. static double make_3dtics(tmin,tmax,axis,logscale, base_log)
  741. double tmin,tmax;
  742. int axis;
  743. TBOOLEAN logscale;
  744. double base_log;
  745. {
  746. int x1,y1,x2,y2;
  747. register double xr,xnorm,tics,tic,l10;
  748.  
  749.     xr = fabs(tmin-tmax);
  750.  
  751.     /* Compute length of axis in screen space coords. */
  752.     switch (axis) {
  753.         case 'x':
  754.             map3d_xy(tmin,0.0,0.0,&x1,&y1);
  755.             map3d_xy(tmax,0.0,0.0,&x2,&y2);
  756.             break;
  757.         case 'y':
  758.             map3d_xy(0.0,tmin,0.0,&x1,&y1);
  759.             map3d_xy(0.0,tmax,0.0,&x2,&y2);
  760.             break;
  761.         case 'z':
  762.             map3d_xy(0.0,0.0,tmin,&x1,&y1);
  763.             map3d_xy(0.0,0.0,tmax,&x2,&y2);
  764.             break;
  765.     }
  766.  
  767.     if (((long) (x1-x2))*(x1-x2) + ((long) (y1-y2))*(y1-y2) <
  768.         sqr(3L * term_tbl[term].h_char))
  769.         return -1.0;                              /* No tics! */
  770.  
  771.     l10 = log10(xr);
  772.     if (logscale) {
  773.         tic = dbl_raise(base_log,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  774.         if (tic < 1.0)
  775.             tic = 1.0;
  776.     } else {
  777.         xnorm = pow(10.0,l10-(double)((l10 >= 0.0 ) ? (int)l10 : ((int)l10-1)));
  778.         if (xnorm <= 5)
  779.             tics = 0.5;
  780.         else tics = 1.0;
  781.         tic = tics * dbl_raise(10.0,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  782.     }
  783.     return(tic);
  784. }
  785.  
  786. do_3dplot(plots, pcount, min_x, max_x, min_y, max_y, min_z, max_z)
  787. struct surface_points *plots;
  788. int pcount;            /* count of plots in linked list */
  789. double min_x, max_x;
  790. double min_y, max_y;
  791. double min_z, max_z;
  792. {
  793. register struct termentry *t = &term_tbl[term];
  794. register int surface;
  795. register struct surface_points *this_plot;
  796. int xl, yl, linetypeOffset = 0;
  797.             /* only a Pyramid would have this many registers! */
  798. double xtemp, ytemp, ztemp, temp;
  799. struct text_label *this_label;
  800. struct arrow_def *this_arrow;
  801. TBOOLEAN scaling;
  802. transform_matrix mat;
  803.  
  804. /* Initiate transformation matrix using the global view variables. */
  805.     mat_rot_z(surface_rot_z, trans_mat);
  806.     mat_rot_x(surface_rot_x, mat);
  807.     mat_mult(trans_mat, trans_mat, mat);
  808.     mat_scale(surface_scale / 2.0, surface_scale / 2.0, surface_scale / 2.0, mat);
  809.     mat_mult(trans_mat, trans_mat, mat);
  810.  
  811. /* modify min_z/max_z so it will zscale properly. */
  812.     ztemp = (max_z - min_z) / (2.0 * surface_zscale);
  813.     temp = (max_z + min_z) / 2.0;
  814.     min_z = temp - ztemp;
  815.     max_z = temp + ztemp;
  816.  
  817. /* store these in variables global to this file */
  818. /* otherwise, we have to pass them around a lot */
  819.     x_min3d = min_x;
  820.     x_max3d = max_x;
  821.     y_min3d = min_y;
  822.     y_max3d = max_y;
  823.     z_min3d = min_z;
  824.     z_max3d = max_z;
  825.  
  826.     /* The extrema need to be set even when a surface is not being
  827.      * drawn.   Without this, gnuplot used to assume that the X and
  828.      * Y axis started at zero.   -RKC
  829.      */
  830.  
  831.     /* find (bottom) left corner of grid */
  832.     min_sx_ox = min_x;
  833.     min_sx_oy = min_y;
  834.     /* find bottom (right) corner of grid */
  835.     min_sy_ox = max_x;
  836.     min_sy_oy = min_y;
  837.  
  838.  
  839.     if (polar)
  840.     int_error("Cannot splot in polar coordinate system.", NO_CARET);
  841.  
  842.     if (z_min3d == VERYLARGE || z_max3d == -VERYLARGE ||
  843.     x_min3d == VERYLARGE || x_max3d == -VERYLARGE ||
  844.     y_min3d == VERYLARGE || y_max3d == -VERYLARGE)
  845.         int_error("all points undefined!", NO_CARET);
  846.  
  847.     /* If we are to draw the bottom grid make sure zmin is updated properly. */
  848.     if (xtics || ytics || grid)
  849.     z_min3d -= (max_z - min_z) * ticslevel;
  850.  
  851. /*  This used be x_max3d == x_min3d, but that caused an infinite loop once. */
  852.     if (fabs(x_max3d - x_min3d) < zero)
  853.     int_error("x_min3d should not equal x_max3d!",NO_CARET);
  854.     if (fabs(y_max3d - y_min3d) < zero)
  855.     int_error("y_min3d should not equal y_max3d!",NO_CARET);
  856.     if (fabs(z_max3d - z_min3d) < zero)
  857.     int_error("z_min3d should not equal z_max3d!",NO_CARET);
  858.  
  859. #ifndef LITE
  860.     if (hidden3d) {
  861.     struct surface_points *plot;
  862.   
  863.         /* Verify data is hidden line removable - grid based. */
  864.           for (plot = plots; plot != NULL; plot = plot->next_sp) {
  865.          if (plot->plot_type == DATA3D && !plot->has_grid_topology){
  866.           fprintf(stderr,"Notice: Cannot remove hidden lines from non grid data\n");
  867.               return(0);
  868.             }
  869.     
  870.         }
  871.     }
  872. #endif /* not LITE */
  873.  
  874. /* INITIALIZE TERMINAL */
  875.     if (!term_init) {
  876.     (*t->init)();
  877.     term_init = TRUE;
  878.     }
  879.     screen_ok = FALSE;
  880.     scaling = (*t->scale)(xsize, ysize);
  881.     (*t->graphics)();
  882.  
  883.     /* now compute boundary for plot (xleft, xright, ytop, ybot) */
  884.     boundary3d(scaling);
  885.  
  886. /* SCALE FACTORS */
  887.     zscale3d = 2.0/(z_max3d - z_min3d);
  888.     yscale3d = 2.0/(y_max3d - y_min3d);
  889.     xscale3d = 2.0/(x_max3d - x_min3d);
  890.  
  891.     (*t->linetype)(-2); /* border linetype */
  892.  
  893. /* PLACE TITLE */
  894.     if (*title != 0) {
  895.         int x, y;
  896.  
  897.         x = title_xoffset * t->h_char;
  898.         y = title_yoffset * t->v_char;
  899.  
  900.         if ((*t->justify_text)(CENTRE)) 
  901.             (*t->put_text)(x+(xleft+xright)/2, 
  902.                        y+ytop+(t->v_char), title);
  903.         else
  904.             (*t->put_text)(x+(xleft+xright)/2 - strlen(title)*(t->h_char)/2,
  905.                        y+ytop+(t->v_char), title);
  906.     }
  907.  
  908. /* PLACE TIMEDATE */
  909.     if (timedate) {
  910.         int x, y;
  911.  
  912.         x = time_xoffset * t->h_char;
  913.         y = time_yoffset * t->v_char;
  914.         dated = time( (time_t *) 0);
  915.         tdate = ctime( &dated);
  916.         tdate[24]='\0';
  917.         if ((*t->text_angle)(1)) {
  918.             if ((*t->justify_text)(CENTRE)) {
  919.                 (*t->put_text)(x+(t->v_char),
  920.                          y+ybot+4*(t->v_char), tdate);
  921.             }
  922.             else {
  923.                 (*t->put_text)(x+(t->v_char),
  924.                          y+ybot+4*(t->v_char)-(t->h_char)*strlen(ylabel)/2, 
  925.                          tdate);
  926.             }
  927.         }
  928.         else {
  929.             (void)(*t->justify_text)(LEFT);
  930.             (*t->put_text)(x,
  931.                          y+ybot-1*(t->v_char), tdate);
  932.         }
  933.         (void)(*t->text_angle)(0);
  934.     }
  935.  
  936. /* PLACE LABELS */
  937.     for (this_label = first_label; this_label!=NULL;
  938.             this_label=this_label->next ) {
  939.         int x,y;
  940.  
  941.         xtemp = LogScale(this_label->x, is_log_x, log_base_log_x, "label", "x");
  942.         ytemp = LogScale(this_label->y, is_log_y, log_base_log_y, "label", "y");
  943.         ztemp = LogScale(this_label->z, is_log_z, log_base_log_z, "label", "z");
  944.             map3d_xy(xtemp,ytemp,ztemp, &x, &y);
  945.  
  946.         if ((*t->justify_text)(this_label->pos)) {
  947.             (*t->put_text)(x,y,this_label->text);
  948.         }
  949.         else {
  950.             switch(this_label->pos) {
  951.                 case  LEFT:
  952.                     (*t->put_text)(x,y,this_label->text);
  953.                     break;
  954.                 case CENTRE:
  955.                     (*t->put_text)(x -
  956.                         (t->h_char)*strlen(this_label->text)/2,
  957.                         y, this_label->text);
  958.                     break;
  959.                 case RIGHT:
  960.                     (*t->put_text)(x -
  961.                         (t->h_char)*strlen(this_label->text),
  962.                         y, this_label->text);
  963.                     break;
  964.             }
  965.          }
  966.      }
  967.  
  968. /* PLACE ARROWS */
  969.     (*t->linetype)(0);    /* arrow line type */
  970.     for (this_arrow = first_arrow; this_arrow!=NULL;
  971.         this_arrow = this_arrow->next ) {
  972.     int sx,sy,ex,ey;
  973.  
  974.     xtemp = LogScale(this_arrow->sx, is_log_x, log_base_log_x, "arrow", "x");
  975.     ytemp = LogScale(this_arrow->sy, is_log_y, log_base_log_y, "arrow", "y");
  976.     ztemp = LogScale(this_arrow->sz, is_log_z, log_base_log_z, "arrow", "z");
  977.     map3d_xy(xtemp,ytemp,ztemp, &sx, &sy);
  978.  
  979.     xtemp = LogScale(this_arrow->ex, is_log_x, log_base_log_x, "arrow", "x");
  980.     ytemp = LogScale(this_arrow->ey, is_log_y, log_base_log_y, "arrow", "y");
  981.     ztemp = LogScale(this_arrow->ez, is_log_z, log_base_log_z, "arrow", "z");
  982.     map3d_xy(xtemp,ytemp,ztemp, &ex, &ey);
  983.  
  984.     (*t->arrow)(sx, sy, ex, ey, this_arrow->head);
  985.     }
  986.  
  987. #ifndef LITE
  988.     if (hidden3d && draw_surface) {
  989.     init_hidden_line_removal();
  990.     reset_hidden_line_removal();
  991.     hidden_active = TRUE;
  992.     }
  993. #endif /* not LITE */
  994.  
  995. /* DRAW SURFACES AND CONTOURS */
  996.     real_z_min3d = min_z;
  997.     real_z_max3d = max_z;
  998.     if (key == -1) {
  999.         xl = xright  - (t->h_tic) - (t->h_char)*5;
  1000.         yl = ytop - (t->v_tic) - (t->v_char);
  1001.     }
  1002.     if (key == 1) {
  1003.         xtemp = LogScale(key_x, is_log_x, log_base_log_x, "key", "x");
  1004.         ytemp = LogScale(key_y, is_log_y, log_base_log_y, "key", "y");
  1005.         ztemp = LogScale(key_z, is_log_z, log_base_log_z, "key", "z");
  1006.         map3d_xy(xtemp,ytemp,ztemp, &xl, &yl);
  1007.     }
  1008.  
  1009. #ifndef LITE
  1010.     if (hidden3d && draw_surface) plot3d_hidden(plots,pcount);
  1011. #endif /* not LITE */
  1012.     this_plot = plots;
  1013.     for (surface = 0;
  1014.          surface < pcount;
  1015.          this_plot = this_plot->next_sp, surface++) {
  1016. #ifndef LITE
  1017.         if ( hidden3d )
  1018.             hidden_no_update = FALSE;
  1019. #endif /* not LITE */
  1020.  
  1021.         if (draw_surface) {
  1022.             (*t->linetype)(this_plot->line_type);
  1023. #ifndef LITE
  1024.             if (hidden3d) {
  1025.             hidden_line_type_above = this_plot->line_type;
  1026.             hidden_line_type_below = this_plot->line_type + 1;
  1027.             }
  1028. #endif /* not LITE */            
  1029.             if (key != 0 && this_plot->title) {
  1030.             if ((*t->justify_text)(RIGHT)) {
  1031.                 clip_put_text(xl,
  1032.                       yl,this_plot->title);
  1033.             }
  1034.             else {
  1035.                 if (inrange(xl-(t->h_char)*strlen(this_plot->title), 
  1036.                     xleft, xright))
  1037.                 clip_put_text(xl-(t->h_char)*strlen(this_plot->title),
  1038.                           yl,this_plot->title);
  1039.             }
  1040.             }
  1041.             
  1042.             switch(this_plot->plot_style) {
  1043.                 case BOXES: /* can't do boxes in 3d yet so use impulses */
  1044.                 case IMPULSES: {
  1045.                 if (key != 0 && this_plot->title) {
  1046.                 clip_move(xl+(t->h_char),yl);
  1047.                 clip_vector(xl+4*(t->h_char),yl);
  1048.                 }
  1049.                 if (!(hidden3d && draw_surface))
  1050.                   plot3d_impulses(this_plot);
  1051.                 break;
  1052.             }
  1053.             case LINES: {
  1054.                 if (key != 0 && this_plot->title) {
  1055.                 clip_move(xl+(int)(t->h_char),yl);
  1056.                 clip_vector(xl+(int)(4*(t->h_char)),yl);
  1057.                 }
  1058.                 if (!(hidden3d && draw_surface))
  1059.                   plot3d_lines(this_plot);
  1060.                 break;
  1061.             }
  1062.             case ERRORBARS:    /* ignored; treat like points */
  1063.             case POINTSTYLE: {
  1064.                 if (key != 0 && this_plot->title 
  1065.                 && !clip_point(xl+2*(t->h_char),yl)) {
  1066.                 (*t->point)(xl+2*(t->h_char),yl,
  1067.                         this_plot->point_type);
  1068.                 }
  1069.                 if (!(hidden3d && draw_surface))
  1070.                   plot3d_points(this_plot);
  1071.                 break;
  1072.             }
  1073.             case LINESPOINTS: {
  1074.                 /* put lines */
  1075.                 if (key != 0 && this_plot->title) {
  1076.                 clip_move(xl+(t->h_char),yl);
  1077.                 clip_vector(xl+4*(t->h_char),yl);
  1078.                 }
  1079.                  if (!(hidden3d && draw_surface))
  1080.                    plot3d_lines(this_plot);
  1081.             
  1082.                 /* put points */
  1083.                 if (key != 0 && this_plot->title 
  1084.                 && !clip_point(xl+2*(t->h_char),yl)) {
  1085.                 (*t->point)(xl+2*(t->h_char),yl,
  1086.                         this_plot->point_type);
  1087.                 }
  1088.                 if (!(hidden3d && draw_surface))
  1089.                   plot3d_points(this_plot);
  1090.                 break;
  1091.             }
  1092.             case DOTS: {
  1093.                 if (key != 0 && this_plot->title
  1094.                 && !clip_point(xl+2*(t->h_char),yl)) {
  1095.                 (*t->point)(xl+2*(t->h_char),yl, -1);
  1096.                 }
  1097.                 if (!(hidden3d && draw_surface))
  1098.                   plot3d_dots(this_plot);
  1099.                 break;
  1100.             }
  1101.             }
  1102.             if (key != 0 && this_plot->title)
  1103.                 yl = yl - (t->v_char);
  1104.         }
  1105.  
  1106. #ifndef LITE
  1107.         if ( hidden3d ) {
  1108.             hidden_no_update = TRUE;
  1109.             hidden_line_type_above = this_plot->line_type + (hidden3d ? 2 : 1);
  1110.             hidden_line_type_below = this_plot->line_type + (hidden3d ? 2 : 1);
  1111.         }
  1112. #endif /* not LITE */
  1113.  
  1114.         if (draw_contour && this_plot->contours != NULL) {
  1115.             struct gnuplot_contours *cntrs = this_plot->contours;
  1116.  
  1117.             (*t->linetype)(this_plot->line_type + (hidden3d ? 2 : 1));
  1118.  
  1119.             if (key != 0 && this_plot->title 
  1120.                       && !(draw_surface && label_contours) ) {
  1121.                 if ((*t->justify_text)(RIGHT)) {
  1122.                     clip_put_text(xl,
  1123.                         yl,this_plot->title);
  1124.                 }
  1125.                 else {
  1126.                     if (inrange(xl-(t->h_char)*strlen(this_plot->title), 
  1127.                              xleft, xright))
  1128.                      clip_put_text(xl-(t->h_char)*strlen(this_plot->title),
  1129.                                  yl,this_plot->title);
  1130.                 }
  1131.                 switch(this_plot->plot_style) {
  1132.                     case IMPULSES:
  1133.                         clip_move(xl+(t->h_char),yl);
  1134.                         clip_vector(xl+4*(t->h_char),yl);
  1135.                         break;
  1136.                     case LINES:
  1137.                         clip_move(xl+(int)(t->h_char),yl);
  1138.                         clip_vector(xl+(int)(4*(t->h_char)),yl);
  1139.                         break;
  1140.                     case ERRORBARS: /* ignored; treat like points */
  1141.                     case POINTSTYLE:
  1142.                         if (!clip_point(xl+2*(t->h_char),yl)) {
  1143.                              (*t->point)(xl+2*(t->h_char),yl,
  1144.                                     this_plot->point_type);
  1145.                         }
  1146.                         break;
  1147.                     case LINESPOINTS:
  1148.                         clip_move(xl+(int)(t->h_char),yl);
  1149.                         clip_vector(xl+(int)(4*(t->h_char)),yl);
  1150.                         break;
  1151.                     case DOTS:
  1152.                         if (!clip_point(xl+2*(t->h_char),yl)) {
  1153.                              (*t->point)(xl+2*(t->h_char),yl, -1);
  1154.                         }
  1155.                         break;
  1156.                 }
  1157.                 yl = yl - (t->v_char);
  1158.             }
  1159.             yl = yl + (t->v_char);
  1160.  
  1161.              linetypeOffset = this_plot->line_type + (hidden3d ? 2 : 1);
  1162.             while (cntrs) {
  1163.                  if(label_contours && cntrs->isNewLevel) {
  1164.                      (*t->linetype)(linetypeOffset++);
  1165. #ifndef LITE
  1166.                      if(hidden3d) hidden_line_type_below = hidden_line_type_above = linetypeOffset-1;
  1167. #endif /* not LITE */
  1168.                      yl -= (t->v_char);
  1169.                      if ((*t->justify_text)(RIGHT)) {
  1170.                         clip_put_text(xl,
  1171.                             yl,cntrs->label);
  1172.                     }
  1173.                     else {
  1174.                         if (inrange(xl-(t->h_char)*strlen(cntrs->label),
  1175.                                  xleft, xright))
  1176.                          clip_put_text(xl-(t->h_char)*strlen(cntrs->label),
  1177.                                      yl,cntrs->label);
  1178.                     }
  1179.                     switch(this_plot->plot_style) {
  1180.                         case IMPULSES:
  1181.                             clip_move(xl+(t->h_char),yl);
  1182.                             clip_vector(xl+4*(t->h_char),yl);
  1183.                             break;
  1184.                         case LINES:
  1185.                             clip_move(xl+(int)(t->h_char),yl);
  1186.                             clip_vector(xl+(int)(4*(t->h_char)),yl);
  1187.                             break;
  1188.                         case ERRORBARS: /* ignored; treat like points */
  1189.                         case POINTSTYLE:
  1190.                             if (!clip_point(xl+2*(t->h_char),yl)) {
  1191.                                  (*t->point)(xl+2*(t->h_char),yl,
  1192.                                         this_plot->point_type);
  1193.                             }
  1194.                             break;
  1195.                         case LINESPOINTS:
  1196.                             clip_move(xl+(int)(t->h_char),yl);
  1197.                             clip_vector(xl+(int)(4*(t->h_char)),yl);
  1198.                             break;
  1199.                         case DOTS:
  1200.                             if (!clip_point(xl+2*(t->h_char),yl)) {
  1201.                                  (*t->point)(xl+2*(t->h_char),yl, -1);
  1202.                             }
  1203.                             break;
  1204.                     }
  1205.                  }
  1206.                 switch(this_plot->plot_style) {
  1207.                     case IMPULSES:
  1208.                            cntr3d_impulses(cntrs, this_plot);
  1209.                         break;
  1210.                     case LINES:
  1211.                         cntr3d_lines(cntrs);
  1212.                         break;
  1213.                     case ERRORBARS: /* ignored; treat like points */
  1214.                     case POINTSTYLE:
  1215.                         cntr3d_points(cntrs, this_plot);
  1216.                         break;
  1217.                     case LINESPOINTS:
  1218.                         cntr3d_lines(cntrs);
  1219.                         cntr3d_points(cntrs, this_plot);
  1220.                         break;
  1221.                     case DOTS:
  1222.                         cntr3d_dots(cntrs);
  1223.                         break;
  1224.                 }
  1225.                 cntrs = cntrs->next;
  1226.             }
  1227.             if (key != 0 && this_plot->title)
  1228.               yl = yl - (t->v_char);
  1229.         }
  1230.  
  1231.         if (surface == 0)
  1232.             draw_bottom_grid(this_plot,real_z_min3d,real_z_max3d);
  1233.     }
  1234.     (*t->text)();
  1235.     (void) fflush(outfile);
  1236.  
  1237. #ifndef LITE
  1238.     if (hidden3d) {
  1239.         term_hidden_line_removal();
  1240.         hidden_active = FALSE;
  1241.     }
  1242. #endif /* not LITE */
  1243. }
  1244.  
  1245. /* plot3d_impulses:
  1246.  * Plot the surfaces in IMPULSES style
  1247.  */
  1248. static plot3d_impulses(plot)
  1249.     struct surface_points *plot;
  1250. {
  1251.     int i;                /* point index */
  1252.     int x,y,x0,y0;            /* point in terminal coordinates */
  1253.     struct iso_curve *icrvs = plot->iso_crvs;
  1254.  
  1255.     while ( icrvs ) {
  1256.     struct coordinate GPHUGE *points = icrvs->points;
  1257.  
  1258.     for (i = 0; i < icrvs->p_count; i++) {
  1259.         if (real_z_max3d<points[i].z)
  1260.         real_z_max3d=points[i].z;
  1261.         if (real_z_min3d>points[i].z)
  1262.         real_z_min3d=points[i].z;
  1263.  
  1264.         map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1265.         map3d_xy(points[i].x, points[i].y, z_min3d, &x0, &y0);
  1266.  
  1267.         clip_move(x0,y0);
  1268.         clip_vector(x,y);
  1269.     }
  1270.  
  1271.     icrvs = icrvs->next;
  1272.     }
  1273. }
  1274.  
  1275. /* plot3d_lines:
  1276.  * Plot the surfaces in LINES style
  1277.  */
  1278. /* We want to always draw the lines in the same direction, otherwise when
  1279.    we draw an adjacent box we might get the line drawn a little differently
  1280.    and we get splotches.  */
  1281.  
  1282. #ifndef LITE
  1283.  
  1284. static int zsort( r1, r2)
  1285. int * r1;
  1286. int * r2;
  1287. {
  1288.   int z1, z2;
  1289.   z1 = nodes[*r1].z;
  1290.   z2 = nodes[*r2].z;
  1291.   if (z1 < z2) return 1;
  1292.   if (z1 == z2) return 0;
  1293.   return -1;
  1294. }
  1295. #define TESTBOX(X,Y)                    \
  1296.   if(X<xmin_box) xmin_box = X;                \
  1297.   if(X>xmax_box) xmax_box = X;                \
  1298.   if(Y<ymin_box) ymin_box = Y;                \
  1299.   if(Y>ymax_box) ymax_box = Y;
  1300. /* Usefull macro to help us figure out which side of the surface we are on */
  1301. #define XPRD(I,J,K)                     \
  1302.   ((nodes[I].x-nodes[J].x)*(nodes[J].y-nodes[K].y) -    \
  1303.   (nodes[I].y-nodes[J].y)*(nodes[J].x-nodes[K].x))
  1304. #define MAYBE_LINEPOINT(J)                        \
  1305.     if((nodes[J].flag & 0x20) != 0) {                \
  1306.       x = nodes[J].x;                        \
  1307.       y = nodes[J].y;                        \
  1308.       nodes[J].flag -= 0x20;                    \
  1309.       if (!clip_point(x,y) &&                     \
  1310.       !IFSET(XREDUCE(x)-XREDUCE(xleft),YREDUCE(y)-YREDUCE(ybot))) \
  1311.     (*t->point)(x,y, plot_info[nplot].point_type);        \
  1312.     };
  1313.  
  1314. struct surface_plots{
  1315.   int above_color;
  1316.   int below_color;
  1317.   int row_offset;
  1318.   int point_type;
  1319. };
  1320. /* All of the plots coming into this routine are assumed to have grid
  1321.    topology.  */
  1322.  
  1323. static plot3d_hidden(plots, pcount)
  1324.      struct surface_points *plots;
  1325.      int pcount;
  1326. {
  1327.   struct surface_points *this_plot;
  1328.   long int i, j;
  1329.   int nplot;
  1330.   long int x,y,z ,nseg, ncrv, ncrv1;        /* point in terminal coordinates */
  1331. #ifdef AMIGA_SC_6_1
  1332.   unsigned short int * cpnt;
  1333. #else /* !AMIGA_SC_6_1 */
  1334.   short int * cpnt;
  1335. #endif /* !AMIGA_SC_6_1 */
  1336.   short int  mask1, mask2;
  1337.   long int indx1, indx2, k, m;
  1338.   short int xmin_box, xmax_box, ymin_box, ymax_box;
  1339.   struct surface_plots * plot_info;
  1340.   int row_offset, nnode;
  1341.   short int y_malloc;  /* Amount of space we need for one vertical row of
  1342.                           bitmap, and byte offset of first used element */
  1343.   struct termentry *t = &term_tbl[term];
  1344.   struct iso_curve *icrvs;
  1345.   int current_style = 0x7fff;  /* Current line style */
  1346.   int surface;
  1347.   nnode = 0;
  1348.   nseg = 0;
  1349.   nplot = 0;
  1350.   this_plot = plots;
  1351.  
  1352.   for (surface = 0;
  1353.        surface < pcount;
  1354.        this_plot = this_plot->next_sp, surface++) {
  1355.     nplot++;
  1356.     icrvs = plots->iso_crvs;
  1357.     icrvs = plots->iso_crvs;
  1358.     if(this_plot->plot_type == FUNC3D) {
  1359.         for(icrvs = this_plot->iso_crvs,ncrv=0;icrvs;icrvs=icrvs->next,ncrv++) { };
  1360.  /*      if(this_plot->has_grid_topology) ncrv >>= 1; */
  1361.     };
  1362.     if(this_plot->plot_type == DATA3D)
  1363.        ncrv = this_plot->num_iso_read;
  1364.     nnode += ncrv * (this_plot->iso_crvs->p_count);
  1365. /*    for(icrvs = this_plot->iso_crvs,ncrv=0;icrvs;icrvs=icrvs->next,ncrv++) { };
  1366.     nnode += ncrv * (this_plot->iso_crvs->p_count); */
  1367.     switch(this_plot->plot_style) {
  1368.     case ERRORBARS:
  1369.     case DOTS:
  1370.     case POINTSTYLE:
  1371.     case LINESPOINTS:
  1372.       nseg += (ncrv) * (this_plot->iso_crvs->p_count);
  1373.       break;
  1374.     case LINES:
  1375.       nseg += (ncrv-1) * (this_plot->iso_crvs->p_count-1);
  1376.       break;
  1377.     case IMPULSES:
  1378.       /* There will be two nodes for each segment */
  1379.       nnode += ncrv * (this_plot->iso_crvs->p_count);
  1380.       nseg += (ncrv) * (this_plot->iso_crvs->p_count);
  1381.       break;
  1382.     }
  1383.   };
  1384.   boxlist = (int *) alloc((unsigned long)sizeof(int)*nseg, "hidden");
  1385.   nodes = (struct pnts *) alloc((unsigned long)sizeof(struct pnts)*nnode, "hidden");
  1386.   plot_info = (struct surface_plots *) alloc((unsigned long)sizeof(struct surface_plots)*nplot,"hidden");
  1387.   nnode = 0;
  1388.   nseg = 0;
  1389.   nplot = 0;
  1390.   this_plot = plots;
  1391.   hidden_no_update = FALSE;
  1392.  
  1393.   if ( hidden3d && draw_surface)
  1394.     for (surface = 0;
  1395.      surface < pcount;
  1396.      this_plot = this_plot->next_sp, surface++) {
  1397.       (*t->linetype)(this_plot->line_type);
  1398.       hidden_line_type_above = this_plot->line_type;
  1399.         hidden_line_type_below = this_plot->line_type + 1;
  1400.     if(this_plot->plot_type == FUNC3D) {
  1401.       for(icrvs = this_plot->iso_crvs,ncrv=0;icrvs;icrvs=icrvs->next,ncrv++) { };
  1402. /*      if(this_plot->has_grid_topology) ncrv >>= 1; */
  1403.     };
  1404.     if(this_plot->plot_type == DATA3D)
  1405.       ncrv = this_plot->num_iso_read;
  1406.       icrvs = this_plot->iso_crvs;
  1407.       ncrv1 = ncrv;
  1408.       ncrv = 0;
  1409.       while ( icrvs) {
  1410.     struct coordinate GPHUGE *points = icrvs->points;
  1411.     for (i = 0; i < icrvs->p_count; i++) {
  1412.       map3d_xy(points[i].x, points[i].y, points[i].z,&nodes[nnode].x,&nodes[nnode].y);
  1413.       nodes[nnode].z = map3d_z(points[i].x, points[i].y, points[i].z);
  1414.       nodes[nnode].flag = (i==0 ? 1 : 0) + (ncrv == 0 ? 2 : 0) +
  1415.         (i == icrvs->p_count-1 ? 4 : 0) + (ncrv == ncrv1-1 ? 8 : 0);
  1416.       nodes[nnode].nplot = nplot;
  1417.       nodes[nnode].style_used = -1000; /* indicates no style */
  1418.       switch(this_plot->plot_style) {
  1419.       case LINESPOINTS:
  1420.         if(i < icrvs->p_count-1 && ncrv < ncrv1-1)
  1421.           nodes[nnode].flag |= 0x30;
  1422.         else
  1423.           nodes[nnode].flag |= 0x20;
  1424.         boxlist[nseg++] = nnode++;
  1425.         break;
  1426.       case LINES:
  1427.         if(i < icrvs->p_count-1 && ncrv < ncrv1-1)
  1428.           {
  1429.         nodes[nnode].flag |= 0x10;
  1430.         boxlist[nseg++] = nnode++;
  1431.           }
  1432.         else
  1433.           nnode++;
  1434.         break;
  1435.       case ERRORBARS:
  1436.       case POINTSTYLE:
  1437.       case DOTS:
  1438.         nodes[nnode].flag |= 0x40;
  1439.         boxlist[nseg++] = nnode++;
  1440.         break;
  1441.       case IMPULSES:
  1442.         nodes[nnode].flag |= 0x80;
  1443.         boxlist[nseg++] = nnode++;
  1444.         map3d_xy(points[i].x, points[i].y, z_min3d, &nodes[nnode].x,&nodes[nnode].y);
  1445.         nodes[nnode].z = map3d_z(points[i].x, points[i].y, z_min3d);
  1446.         nnode++;
  1447.         break;
  1448.         break;
  1449.       }
  1450.     }
  1451.     icrvs = icrvs->next;
  1452.     ncrv++;
  1453.     if(ncrv == ncrv1) break;
  1454.       }
  1455.       /* Next we go through all of the boxes, and substitute the average z value
  1456.      for the box for the z value of the corner node */
  1457.       plot_info[nplot].above_color = this_plot->line_type;
  1458.       plot_info[nplot].below_color = this_plot->line_type+1;
  1459.       plot_info[nplot].point_type =
  1460.     ((this_plot->plot_style == DOTS) ? -1 : this_plot->point_type);
  1461.       plot_info[nplot++].row_offset = this_plot->iso_crvs->p_count;
  1462.     }
  1463.       for(i=0; i<nseg; i++){
  1464.     j = boxlist[i];
  1465.     if ((nodes[j].flag & 0x80) != 0) {
  1466.       nodes[j].z = (nodes[j].z < nodes[j+1].z ? nodes[j].z : nodes[j+1].z);
  1467.       continue;
  1468.     };
  1469.     if ((nodes[j].flag & 0x10) == 0) continue;
  1470.     row_offset = plot_info[nodes[j].nplot].row_offset;
  1471.     z = nodes[j].z;
  1472.     if (z < nodes[j+1].z) z = nodes[j+1].z;
  1473.     if (z < nodes[j+row_offset].z) z = nodes[j+row_offset].z;
  1474.     if (z < nodes[j+row_offset+1].z) z = nodes[j+row_offset+1].z;
  1475.       };
  1476.   qsort (boxlist, nseg, sizeof(int), zsort);
  1477.   y_malloc = (2+ (YREDUCE(ytop)>>4) - (YREDUCE(ybot)>>4))*sizeof(short int);
  1478.   for(i=0;i<=(XREDUCE(xright)-XREDUCE(xleft));i++) {
  1479.     ymin_hl[i] = 0x7fff; 
  1480.     ymax_hl[i] = 0;
  1481.   };
  1482.   for(i=0;i<nseg;i++) {
  1483.     j = boxlist[i];
  1484.     nplot = nodes[j].nplot;
  1485.     row_offset = plot_info[nplot].row_offset;
  1486.     if((nodes[j].flag & 0x40) != 0) {
  1487.       x = nodes[j].x;
  1488.       y = nodes[j].y;
  1489.       if (!clip_point(x,y) &&
  1490.       !IFSET(XREDUCE(x)-XREDUCE(xleft),YREDUCE(y)-YREDUCE(ybot)))
  1491.     (*t->point)(x,y, plot_info[nplot].point_type);
  1492.     };
  1493.     if((nodes[j].flag & 0x80) != 0) { /* impulses */
  1494.       clip_move(nodes[j].x,nodes[j].y);
  1495.       clip_vector(nodes[j+1].x,nodes[j+1].y);
  1496.     };
  1497.     if((nodes[j].flag & 0x10) != 0) {
  1498. /* It is possible, and often profitable, to take a quick look and see
  1499.    if the current box is entirely obscured.  If this is the case we will
  1500.    not even bother testing this box any further.  */
  1501.       xmin_box = 0x7fff; 
  1502.       xmax_box = 0;
  1503.       ymin_box = 0x7fff; 
  1504.       ymax_box = 0;
  1505.       TESTBOX(nodes[j].x-xleft,nodes[j].y-ybot);
  1506.       TESTBOX(nodes[j+1].x-xleft,nodes[j+1].y-ybot);
  1507.       TESTBOX(nodes[j+row_offset].x-xleft,nodes[j+row_offset].y-ybot);
  1508.       TESTBOX(nodes[j+row_offset+1].x-xleft,nodes[j+row_offset+1].y-ybot);
  1509.       z=0;
  1510.       if(xmin_box < 0) xmin_box = 0;
  1511.       if(ymin_box < 0) ymin_box = 0;
  1512.       if(xmax_box > xright-xleft) xmax_box = xright-xleft;
  1513.       if(ymax_box > ytop-ybot) ymax_box = ytop-ybot;
  1514.       /* Now check bitmap.  These coordinates have not been reduced */
  1515.       if(xmin_box <= xmax_box && ymin_box <= ymax_box){
  1516.     ymin_box = YREDUCE(ymin_box);
  1517.     ymax_box = YREDUCE(ymax_box);
  1518.     xmin_box = XREDUCE(xmin_box);
  1519.     xmax_box = XREDUCE(xmax_box);
  1520.     indx1 = ymin_box >> 4;
  1521.     indx2 = ymax_box >> 4;
  1522.     mask1 = 0xffff << (ymin_box & 0x0f);
  1523.     mask2 = 0xffff >> (0x0f-(ymax_box & 0x0f));
  1524.     for(m=xmin_box;m<=xmax_box;m++) {
  1525.       if(pnt[m] == 0) {z++; break;};
  1526.       cpnt = pnt[m] + indx1;
  1527.       if(indx1 == indx2){
  1528.         if((*cpnt & mask1 & mask2) != (mask1 & mask2)) {z++; break;}
  1529.       } else {
  1530.         if((*cpnt++ & mask1) != mask1) {z++; break;}
  1531.         k = indx1+1;
  1532.         while (k != indx2) {
  1533.           if((unsigned short)*cpnt++ != 0xffff) {z++; break;}
  1534.           k++;
  1535.         };
  1536.         if((*cpnt++ & mask2) != mask2) {z++; break;}
  1537.       };
  1538.     };
  1539.       };
  1540.       /* z is 0 if all of the pixels used by the current box are already covered.
  1541.      No point in proceeding, so we just skip all further processing of this
  1542.      box. */
  1543.       if(!z) continue;
  1544.       /* Now we need to figure out whether we are looking at the top or the
  1545.      bottom of the square.  A simple cross product will tell us this.
  1546.      If the square is really distorted then this will not be accurate,
  1547.      but in such cases we would actually be seeing both sides at the same
  1548.      time.  We choose the vertex with the largest z component to
  1549.      take the cross product at.  */
  1550.       {
  1551.     int z1, z2 ,z3, z4;
  1552.     z1 = XPRD(j+row_offset,j,j+1);
  1553.     z2 = XPRD(j,j+1,j+1+row_offset);
  1554.     z3 = XPRD(j+1,j+row_offset+1,j+row_offset);
  1555.     z4 = XPRD(j+row_offset+1,j+row_offset,j);
  1556.     z=0;
  1557.     z += (z1 > 0 ? 1 : -1);
  1558.     z += (z2 > 0 ? 1 : -1);
  1559.     z += (z3 > 0 ? 1 : -1);
  1560.     z += (z4 > 0 ? 1 : -1);
  1561.     /* See if the box is uniformly one side or another. */
  1562.     if(z != 4 && z != -4) {
  1563. /* It isn't.  Now find the corner of the box with the largest z value that
  1564.    has already been plotted, and use the same style used for that node.  */
  1565.       k = -1000;
  1566.       x = -32768;
  1567.       if (nodes[j].z > x && nodes[j].style_used !=-1000) {
  1568.         k = nodes[j].style_used;
  1569.         x = nodes[j].z;
  1570.       };
  1571.       if (nodes[j+1].z > x && nodes[j+1].style_used !=-1000) {
  1572.         k = nodes[j+1].style_used;
  1573.         x = nodes[j+1].z;
  1574.       };
  1575.       if (nodes[j+row_offset+1].z > x && nodes[j+row_offset+1].style_used !=-1000) {
  1576.         k = nodes[j+row_offset+1].style_used;
  1577.         x = nodes[j+row_offset+1].z;
  1578.       };
  1579.       if (nodes[j+row_offset].z > x && nodes[j+row_offset].style_used !=-1000) {
  1580.         k = nodes[j+row_offset].style_used;
  1581.         x = nodes[j+row_offset].z;
  1582.       };
  1583.       if( k != -1000){
  1584.         z = 0; /* To defeat the logic to come.  */
  1585.         current_style = k;
  1586.         (*t->linetype)(current_style);
  1587.       };
  1588.     };
  1589.     /* If k == -1000 then no corner found.  I guess it does not matter.  */
  1590.       };
  1591.       if(z > 0 && current_style != plot_info[nplot].above_color) {
  1592.     current_style = plot_info[nplot].above_color;
  1593.     (*t->linetype)(current_style);
  1594.       };
  1595.       if(z < 0 && current_style != plot_info[nplot].below_color) {
  1596.     current_style = plot_info[nplot].below_color;
  1597.     (*t->linetype)(current_style);
  1598.       };
  1599.       xmin_hl = (sizeof(xleft) == 4 ? 0x7fffffff : 0x7fff ); 
  1600.       xmax_hl = 0;
  1601.       clip_move(nodes[j].x,nodes[j].y);
  1602.       clip_vector(nodes[j+1].x,nodes[j+1].y);
  1603.       clip_vector(nodes[j+row_offset+1].x,nodes[j+row_offset+1].y);
  1604.       clip_vector(nodes[j+row_offset].x,nodes[j+row_offset].y);
  1605.       clip_vector(nodes[j].x,nodes[j].y);
  1606.       nodes[j].style_used = current_style;
  1607.       nodes[j+1].style_used = current_style;
  1608.       nodes[j+row_offset+1].style_used = current_style;
  1609.       nodes[j+row_offset].style_used = current_style;
  1610.       MAYBE_LINEPOINT(j);
  1611.       MAYBE_LINEPOINT(j+1);
  1612.       MAYBE_LINEPOINT(j+row_offset+1);
  1613.       MAYBE_LINEPOINT(j+row_offset);
  1614.       if( xmin_hl < 0 || xmax_hl > XREDUCE(xright)-XREDUCE(xleft))
  1615.     int_error("Logic error #3 in hidden line",NO_CARET);
  1616.       /* now mark the area as being filled in the bitmap.  These coordinates
  1617.          have already been reduced. */
  1618.       if (xmin_hl < xmax_hl)
  1619.     for(j=xmin_hl;j<=xmax_hl;j++) {
  1620.       if (ymin_hl[j] == 0x7fff) 
  1621.         int_error("Logic error #2 in hidden line",NO_CARET);
  1622.       if(pnt[j] == 0) {
  1623.         pnt[j] = (short int *) alloc((unsigned long)y_malloc,"hidden");
  1624.         bzero(pnt[j],y_malloc);
  1625.       };
  1626.       if(ymin_hl[j] < 0 || ymax_hl[j] > YREDUCE(ytop)-YREDUCE(ybot))
  1627.         int_error("Logic error #1 in hidden line",NO_CARET);
  1628. /* this shift is wordsize dependent */
  1629.       indx1 = ymin_hl[j] >> 4;
  1630.       indx2 = ymax_hl[j] >> 4;
  1631.       mask1 = 0xffff << (ymin_hl[j] & 0xf);
  1632.       mask2 = 0xffff >> (0xf-(ymax_hl[j] & 0xf));
  1633.       cpnt = pnt[j] + indx1;
  1634.       if(indx1 == indx2){
  1635.         *cpnt |= (mask1 & mask2);
  1636.       } else {
  1637.         *cpnt++ |= mask1;
  1638.         k = indx1+1;
  1639.         while (k != indx2) {
  1640.           *cpnt++ = 0xffff; 
  1641.           k++;
  1642.         };
  1643.         *cpnt |= mask2;
  1644.       };
  1645.       ymin_hl[j]=0x7fff; 
  1646.       ymax_hl[j]=0;
  1647.     };
  1648.     };
  1649.   };
  1650.   free(nodes);
  1651.   free(boxlist);
  1652.   free(plot_info);
  1653. }
  1654.  
  1655. #endif /* not LITE */
  1656.  
  1657. static plot3d_lines(plot)
  1658.     struct surface_points *plot;
  1659. {
  1660.     int i;
  1661.     int x,y;                /* point in terminal coordinates */
  1662.     struct iso_curve *icrvs = plot->iso_crvs;
  1663.     struct coordinate GPHUGE *points;
  1664.  
  1665. #ifndef LITE
  1666. /* These are handled elsewhere.  */
  1667.     if (plot->has_grid_topology && hidden3d)
  1668.     return(0);
  1669. #endif /* not LITE */
  1670.  
  1671.     while (icrvs) {
  1672.  
  1673.     for (i = 0, points = icrvs->points; i < icrvs->p_count; i++) {
  1674.         if (real_z_max3d<points[i].z)
  1675.         real_z_max3d=points[i].z;
  1676.         if (real_z_min3d>points[i].z)
  1677.         real_z_min3d=points[i].z;
  1678.  
  1679.         map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1680.  
  1681.         if (i > 0)
  1682.         clip_vector(x,y);
  1683.         else
  1684.         clip_move(x,y);
  1685.     }
  1686.  
  1687.     icrvs = icrvs->next;
  1688.     }
  1689. }
  1690.  
  1691. /* plot3d_points:
  1692.  * Plot the surfaces in POINTSTYLE style
  1693.  */
  1694. static plot3d_points(plot)
  1695.     struct surface_points *plot;
  1696. {
  1697.     int i,x,y;
  1698.     struct termentry *t = &term_tbl[term];
  1699.     struct iso_curve *icrvs = plot->iso_crvs;
  1700.  
  1701.     while ( icrvs ) {
  1702.     struct coordinate GPHUGE *points = icrvs->points;
  1703.  
  1704.     for (i = 0; i < icrvs->p_count; i++) {
  1705.         if (real_z_max3d<points[i].z)
  1706.         real_z_max3d=points[i].z;
  1707.         if (real_z_min3d>points[i].z)
  1708.         real_z_min3d=points[i].z;
  1709.  
  1710.         map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1711.  
  1712.         if (!clip_point(x,y))
  1713.         (*t->point)(x,y, plot->point_type);
  1714.     }
  1715.  
  1716.     icrvs = icrvs->next;
  1717.     }
  1718. }
  1719.  
  1720. /* plot3d_dots:
  1721.  * Plot the surfaces in DOTS style
  1722.  */
  1723. static plot3d_dots(plot)
  1724.     struct surface_points *plot;
  1725. {
  1726.     int i,x,y;
  1727.     struct termentry *t = &term_tbl[term];
  1728.     struct iso_curve *icrvs = plot->iso_crvs;
  1729.  
  1730.     while ( icrvs ) {
  1731.     struct coordinate GPHUGE *points = icrvs->points;
  1732.  
  1733.         for (i = 0; i < icrvs->p_count; i++) {
  1734.         if (real_z_max3d<points[i].z)
  1735.         real_z_max3d=points[i].z;
  1736.         if (real_z_min3d>points[i].z)
  1737.             real_z_min3d=points[i].z;
  1738.  
  1739.             map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1740.  
  1741.             if (!clip_point(x,y))
  1742.         (*t->point)(x,y, -1);
  1743.         }
  1744.  
  1745.     icrvs = icrvs->next;
  1746.     }
  1747. }
  1748.  
  1749. /* cntr3d_impulses:
  1750.  * Plot a surface contour in IMPULSES style
  1751.  */
  1752. static cntr3d_impulses(cntr, plot)
  1753.     struct gnuplot_contours *cntr;
  1754.     struct surface_points *plot;
  1755. {
  1756.     int i;                /* point index */
  1757.     int x,y,x0,y0;            /* point in terminal coordinates */
  1758.  
  1759.     if (draw_contour == CONTOUR_SRF || draw_contour == CONTOUR_BOTH) {
  1760.     for (i = 0; i < cntr->num_pts; i++) {
  1761.         if (real_z_max3d<cntr->coords[i].z)
  1762.         real_z_max3d=cntr->coords[i].z;
  1763.         if (real_z_min3d>cntr->coords[i].z)
  1764.         real_z_min3d=cntr->coords[i].z;
  1765.  
  1766.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
  1767.              &x, &y);
  1768.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, z_min3d,
  1769.              &x0, &y0);
  1770.  
  1771.         clip_move(x0,y0);
  1772.         clip_vector(x,y);
  1773.     }
  1774.     }
  1775.     else
  1776.     cntr3d_points(cntr, plot);   /* Must be on base grid, so do points. */
  1777. }
  1778.  
  1779. /* cntr3d_lines:
  1780.  * Plot a surface contour in LINES style
  1781.  */
  1782. static cntr3d_lines(cntr)
  1783.     struct gnuplot_contours *cntr;
  1784. {
  1785.     int i;                /* point index */
  1786.     int x,y;                /* point in terminal coordinates */
  1787.  
  1788.     if (draw_contour == CONTOUR_SRF || draw_contour == CONTOUR_BOTH) {
  1789.     for (i = 0; i < cntr->num_pts; i++) {
  1790.         if (real_z_max3d<cntr->coords[i].z)
  1791.         real_z_max3d=cntr->coords[i].z;
  1792.         if (real_z_min3d>cntr->coords[i].z)
  1793.         real_z_min3d=cntr->coords[i].z;
  1794.  
  1795.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
  1796.                  &x, &y);
  1797.  
  1798.              if (i > 0) {
  1799.                  clip_vector(x,y);
  1800.                  if(i == 1) suppressMove = TRUE;
  1801.              } else {
  1802.                  clip_move(x,y);
  1803.              }
  1804.         }
  1805.     }
  1806.      suppressMove = FALSE;  /* beginning a new contour level, so moveto() required */
  1807.  
  1808.     if (draw_contour == CONTOUR_BASE || draw_contour == CONTOUR_BOTH) {
  1809.     for (i = 0; i < cntr->num_pts; i++) {
  1810.         if (real_z_max3d<cntr->coords[i].z)
  1811.         real_z_max3d=cntr->coords[i].z;
  1812.         if (real_z_min3d>cntr->coords[i].z)
  1813.         real_z_min3d=cntr->coords[i].z;
  1814.  
  1815.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, z_min3d,
  1816.                  &x, &y);
  1817.  
  1818.              if (i > 0) {
  1819.                  clip_vector(x,y);
  1820.                  if(i == 1) suppressMove = TRUE;
  1821.              } else {
  1822.                  clip_move(x,y);
  1823.              }
  1824.          }
  1825.      }
  1826.      suppressMove = FALSE;  /* beginning a new contour level, so moveto() required */
  1827. }
  1828.  
  1829. /* cntr3d_points:
  1830.  * Plot a surface contour in POINTSTYLE style
  1831.  */
  1832. static cntr3d_points(cntr, plot)
  1833.     struct gnuplot_contours *cntr;
  1834.     struct surface_points *plot;
  1835. {
  1836.     int i;
  1837.     int x,y;
  1838.     struct termentry *t = &term_tbl[term];
  1839.  
  1840.     if (draw_contour == CONTOUR_SRF || draw_contour == CONTOUR_BOTH) {
  1841.     for (i = 0; i < cntr->num_pts; i++) {
  1842.         if (real_z_max3d<cntr->coords[i].z)
  1843.         real_z_max3d=cntr->coords[i].z;
  1844.         if (real_z_min3d>cntr->coords[i].z)
  1845.         real_z_min3d=cntr->coords[i].z;
  1846.  
  1847.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
  1848.                  &x, &y);
  1849.  
  1850.         if (!clip_point(x,y))
  1851.         (*t->point)(x,y, plot->point_type);
  1852.         }
  1853.     }
  1854.  
  1855.     if (draw_contour == CONTOUR_BASE || draw_contour == CONTOUR_BOTH) {
  1856.     for (i = 0; i < cntr->num_pts; i++) {
  1857.         if (real_z_max3d<cntr->coords[i].z)
  1858.         real_z_max3d=cntr->coords[i].z;
  1859.         if (real_z_min3d>cntr->coords[i].z)
  1860.         real_z_min3d=cntr->coords[i].z;
  1861.  
  1862.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, z_min3d,
  1863.                  &x, &y);
  1864.  
  1865.         if (!clip_point(x,y))
  1866.         (*t->point)(x,y, plot->point_type);
  1867.         }
  1868.     }
  1869. }
  1870.  
  1871. /* cntr3d_dots:
  1872.  * Plot a surface contour in DOTS style
  1873.  */
  1874. static cntr3d_dots(cntr)
  1875.     struct gnuplot_contours *cntr;
  1876. {
  1877.     int i;
  1878.     int x,y;
  1879.     struct termentry *t = &term_tbl[term];
  1880.  
  1881.     if (draw_contour == CONTOUR_SRF || draw_contour == CONTOUR_BOTH) {
  1882.     for (i = 0; i < cntr->num_pts; i++) {
  1883.         if (real_z_max3d<cntr->coords[i].z)
  1884.         real_z_max3d=cntr->coords[i].z;
  1885.         if (real_z_min3d>cntr->coords[i].z)
  1886.         real_z_min3d=cntr->coords[i].z;
  1887.  
  1888.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
  1889.                  &x, &y);
  1890.  
  1891.         if (!clip_point(x,y))
  1892.         (*t->point)(x,y, -1);
  1893.         }
  1894.     }
  1895.  
  1896.     if (draw_contour == CONTOUR_BASE || draw_contour == CONTOUR_BOTH) {
  1897.     for (i = 0; i < cntr->num_pts; i++) {
  1898.         if (real_z_max3d<cntr->coords[i].z)
  1899.         real_z_max3d=cntr->coords[i].z;
  1900.         if (real_z_min3d>cntr->coords[i].z)
  1901.         real_z_min3d=cntr->coords[i].z;
  1902.  
  1903.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, z_min3d,
  1904.                  &x, &y);
  1905.  
  1906.         if (!clip_point(x,y))
  1907.         (*t->point)(x,y, -1);
  1908.         }
  1909.     }
  1910. }
  1911.  
  1912. static update_extrema_pts(ix, iy, min_sx_x, min_sx_y, min_sy_x, min_sy_y,
  1913.               x, y)
  1914.     int ix, iy, *min_sx_x, *min_sx_y, *min_sy_x, *min_sy_y;
  1915.     double x, y;
  1916. {
  1917.  
  1918.     if (*min_sx_x > ix + 2 ||         /* find (bottom) left corner of grid */
  1919.     (abs(*min_sx_x - ix) <= 2 && *min_sx_y > iy)) {
  1920.     *min_sx_x = ix;
  1921.     *min_sx_y = iy;
  1922.     min_sx_ox = x;
  1923.     min_sx_oy = y;
  1924.     }
  1925.     if (*min_sy_y > iy + 2 ||         /* find bottom (right) corner of grid */
  1926.     (abs(*min_sy_y - iy) <= 2 && *min_sy_x < ix)) {
  1927.     *min_sy_x = ix;
  1928.     *min_sy_y = iy;
  1929.     min_sy_ox = x;
  1930.     min_sy_oy = y;
  1931.     }
  1932. }
  1933.  
  1934. /* Draw the bottom grid for the parametric case. */
  1935. static draw_parametric_grid(plot)
  1936.     struct surface_points *plot;
  1937. {
  1938.     int i,ix,iy,            /* point in terminal coordinates */
  1939.     min_sx_x = 10000,min_sx_y = 10000,min_sy_x = 10000,min_sy_y = 10000,
  1940.         grid_iso_1 = plot->plot_type == DATA3D && plot->has_grid_topology ?
  1941.                     plot->iso_crvs->p_count : iso_samples_1,
  1942.         grid_iso_2 = plot->plot_type == DATA3D && plot->has_grid_topology ?
  1943.                     plot->num_iso_read : iso_samples_2;
  1944.     double x,y,dx,dy;
  1945.  
  1946.     if (grid && plot->has_grid_topology) {
  1947.  
  1948.     /* fix grid lines to tic marks, D. Taber, 02-01-93 */
  1949.     if(xtics && xticdef.type == TIC_SERIES) {
  1950.         dx = xticdef.def.series.incr;
  1951.         x = xticdef.def.series.start;
  1952.         grid_iso_1 = 1 + (xticdef.def.series.end - x) / dx;
  1953.     } else {
  1954.         x = x_min3d;
  1955.     dx = (x_max3d-x_min3d) / (grid_iso_1-1);
  1956.     }
  1957.  
  1958.     if(ytics && yticdef.type == TIC_SERIES) {
  1959.         dy = yticdef.def.series.incr;
  1960.         y = yticdef.def.series.start;
  1961.         grid_iso_2 = 1 + (yticdef.def.series.end - y) / dy;
  1962.     } else {
  1963.         y = y_min3d;
  1964.     dy = (y_max3d-y_min3d) / (grid_iso_2-1);
  1965.     }
  1966.  
  1967.     for (i = 0; i < grid_iso_2; i++) {
  1968.             if (i == 0 || i == grid_iso_2-1)            
  1969.             setlinestyle(-2);
  1970.         else
  1971.             setlinestyle(-1);
  1972.         map3d_xy(x_min3d, y, z_min3d, &ix, &iy);
  1973.         clip_move(ix,iy);
  1974.         update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  1975.                    &min_sy_x,&min_sy_y,x_min3d,y);
  1976.  
  1977.         map3d_xy(x_max3d, y, z_min3d, &ix, &iy);
  1978.         clip_vector(ix,iy);
  1979.         update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  1980.                    &min_sy_x,&min_sy_y,x_max3d,y);
  1981.  
  1982.         y += dy;
  1983.     }
  1984.  
  1985.     for (i = 0; i < grid_iso_1; i++) {
  1986.             if (i == 0 || i == grid_iso_1-1)
  1987.             setlinestyle(-2);
  1988.         else
  1989.             setlinestyle(-1);
  1990.         map3d_xy(x, y_min3d, z_min3d, &ix, &iy);
  1991.         clip_move(ix,iy);
  1992.         update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  1993.                    &min_sy_x,&min_sy_y,x,y_min3d);
  1994.  
  1995.         map3d_xy(x, y_max3d, z_min3d, &ix, &iy);
  1996.         clip_vector(ix,iy);
  1997.         update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  1998.                    &min_sy_x,&min_sy_y,x,y_max3d);
  1999.  
  2000.         x += dx;
  2001.     }
  2002.     }
  2003.     else {
  2004.     setlinestyle(-2);
  2005.  
  2006.     map3d_xy(x_min3d, y_min3d, z_min3d, &ix, &iy);
  2007.     clip_move(ix,iy);
  2008.     update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  2009.                &min_sy_x,&min_sy_y,x_min3d,y_min3d);
  2010.  
  2011.     map3d_xy(x_max3d, y_min3d, z_min3d, &ix, &iy);
  2012.     clip_vector(ix,iy);
  2013.     update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  2014.                &min_sy_x,&min_sy_y,x_max3d,y_min3d);
  2015.  
  2016.     map3d_xy(x_max3d, y_max3d, z_min3d, &ix, &iy);
  2017.     clip_vector(ix,iy);
  2018.     update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  2019.                &min_sy_x,&min_sy_y,x_max3d,y_max3d);
  2020.  
  2021.     map3d_xy(x_min3d, y_max3d, z_min3d, &ix, &iy);
  2022.     clip_vector(ix,iy);
  2023.     update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  2024.                &min_sy_x,&min_sy_y,x_min3d,y_max3d);
  2025.  
  2026.  
  2027.     map3d_xy(x_min3d, y_min3d, z_min3d, &ix, &iy);
  2028.     clip_vector(ix,iy);
  2029.     }
  2030. }
  2031.  
  2032. /* Draw the bottom grid for non parametric case. */
  2033. static draw_non_param_grid(plot)
  2034.     struct surface_points *plot;
  2035. {
  2036.     int i,is_boundary=TRUE,crv_count=0,
  2037.     x,y,                /* point in terminal coordinates */
  2038.     min_sx_x = 10000,min_sx_y = 10000,min_sy_x = 10000,min_sy_y = 10000,
  2039.         grid_iso = plot->plot_type == DATA3D && plot->has_grid_topology ?
  2040.                     plot->num_iso_read : iso_samples_2;
  2041.     struct iso_curve *icrvs = plot->iso_crvs;
  2042.  
  2043.     while ( icrvs ) {
  2044.     struct coordinate GPHUGE *points = icrvs->points;
  2045.     int saved_hidden_active = hidden_active;
  2046.     int z1 = map3d_z(points[0].x, points[0].y, 0.0),
  2047.            z2 = map3d_z(points[icrvs->p_count-1].x,
  2048.                             points[icrvs->p_count-1].y, 0.0);
  2049.  
  2050.     for (i = 0; i < icrvs->p_count; i += icrvs->p_count-1) {
  2051.         map3d_xy(points[i].x, points[i].y, z_min3d, &x, &y);
  2052.         if (is_boundary) {
  2053.         setlinestyle(-2);
  2054.         }
  2055.         else {
  2056.             setlinestyle(-1);
  2057.         }
  2058.  
  2059.         if (i > 0) {
  2060.             clip_vector(x,y);
  2061.         }
  2062.         else {
  2063.             clip_move(x,y);
  2064.         }
  2065.  
  2066.         if (draw_surface &&
  2067.             is_boundary &&
  2068.             (i == 0 || i == icrvs->p_count-1)) {
  2069.             int x1,y1;            /* point in terminal coordinates */
  2070.  
  2071.         /* Draw a vertical line to surface corner from grid corner. */
  2072.             map3d_xy(points[i].x, points[i].y, points[i].z, &x1, &y1);
  2073. #ifndef LITE
  2074.             if (hidden3d) {
  2075.             if ((i == 0 && z1 > z2) ||
  2076.                 (i == icrvs->p_count-1 && z2 > z1)) {
  2077.                 hidden_active = FALSE; /* This one is always visible. */
  2078.             }                
  2079.             }
  2080. #endif /* not LITE */
  2081.             clip_vector(x1,y1);
  2082.             clip_move(x,y);
  2083.         hidden_active = saved_hidden_active;
  2084.         update_extrema_pts(x,y,&min_sx_x,&min_sx_y, &min_sy_x,&min_sy_y,
  2085.                    points[i].x,points[i].y);
  2086.         }
  2087.     }
  2088.  
  2089.     if (grid) {
  2090.         crv_count++;
  2091.         icrvs = icrvs->next;
  2092.         is_boundary = crv_count == grid_iso - 1 ||
  2093.               crv_count == grid_iso ||
  2094.               (icrvs && icrvs->next == NULL);
  2095.     }
  2096.     else {
  2097.         switch (crv_count++) {
  2098.         case 0:
  2099.             for (i = 0; i < grid_iso - 1; i++)
  2100.             icrvs = icrvs->next;
  2101.             break;
  2102.         case 1:
  2103.             icrvs = icrvs->next;
  2104.             break;
  2105.         case 2:
  2106.             while (icrvs->next)
  2107.             icrvs = icrvs->next;
  2108.             break;
  2109.         case 3:
  2110.             icrvs = NULL;
  2111.             break;
  2112.         }
  2113.         }
  2114.     }
  2115.     if(hidden3d){
  2116.       struct iso_curve *lcrvs = plot->iso_crvs;
  2117.       struct coordinate GPHUGE *points, GPHUGE *lpoints;
  2118.       icrvs = lcrvs;
  2119.       while(lcrvs->next) lcrvs = lcrvs->next;
  2120.       points = icrvs->points;
  2121.       lpoints = lcrvs->points;
  2122.       is_boundary = TRUE;
  2123.       for (i = 0; i < icrvs->p_count; i += (grid ? 1 : icrvs->p_count - 1)) {
  2124.     if ((i == 0) || (i == icrvs->p_count - 1)) {
  2125.       setlinestyle(-2);
  2126.     }
  2127.     else {
  2128.       setlinestyle(-1);
  2129.     }
  2130.     map3d_xy(points[i].x, points[i].y, z_min3d, &x, &y);
  2131.     clip_move(x, y);
  2132.     map3d_xy(lpoints[i].x, lpoints[i].y, z_min3d, &x, &y);
  2133.     clip_vector(x, y);
  2134.       };
  2135.     };
  2136. }
  2137.  
  2138. /* Draw the bottom grid that hold the tic marks for 3d surface. */
  2139. static draw_bottom_grid(plot, min_z, max_z)
  2140.     struct surface_points *plot;
  2141.     double min_z, max_z;
  2142. {
  2143.     int x,y;    /* point in terminal coordinates */
  2144.     double xtic,ytic,ztic;
  2145.     struct termentry *t = &term_tbl[term];
  2146.  
  2147.     xtic = make_3dtics(x_min3d,x_max3d,'x',is_log_x,base_log_x);
  2148.     ytic = make_3dtics(y_min3d,y_max3d,'y',is_log_y,base_log_y);
  2149.     ztic = make_3dtics(min_z,max_z,'z',is_log_z,base_log_z);
  2150.  
  2151.     if (draw_border)
  2152.     if (parametric || !plot->has_grid_topology)
  2153.         draw_parametric_grid(plot);
  2154.     else
  2155.         draw_non_param_grid(plot);
  2156.  
  2157.     setlinestyle(-2); /* border linetype */
  2158.  
  2159. /* label x axis tics */
  2160.     if (xtics && xtic > 0.0) {
  2161.         switch (xticdef.type) {
  2162.             case TIC_COMPUTED:
  2163.          if (x_min3d < x_max3d)
  2164.             draw_3dxtics(xtic * floor(x_min3d/xtic),
  2165.                      xtic,
  2166.                      xtic * ceil(x_max3d/xtic),
  2167.                      min_sy_oy);
  2168.                 else
  2169.             draw_3dxtics(xtic * floor(x_max3d/xtic),
  2170.                      xtic,
  2171.                      xtic * ceil(x_min3d/xtic),
  2172.                      min_sy_oy);
  2173.             break;
  2174.         case TIC_MONTH:
  2175.         draw_month_3dxtics(min_sy_oy);
  2176.         break;
  2177.         case TIC_DAY:
  2178.         draw_day_3dxtics(min_sy_oy);
  2179.         break;
  2180.         case TIC_SERIES:
  2181.         draw_series_3dxtics(xticdef.def.series.start, 
  2182.                     xticdef.def.series.incr, 
  2183.                     xticdef.def.series.end,
  2184.                     min_sy_oy);
  2185.         break;
  2186.         case TIC_USER:
  2187.         draw_set_3dxtics(xticdef.def.user,
  2188.                  min_sy_oy);
  2189.         break;
  2190.             default:
  2191.             (*t->text)();
  2192.             (void) fflush(outfile);
  2193.             int_error("unknown tic type in xticdef in do_3dplot", NO_CARET);
  2194.             break;        /* NOTREACHED */
  2195.         }
  2196.     }
  2197. /* label y axis tics */
  2198.     if (ytics && (ytic > 0.0)) {
  2199.         switch (yticdef.type) {
  2200.             case TIC_COMPUTED:
  2201.          if (y_min3d < y_max3d) {
  2202.             draw_3dytics(ytic * floor(y_min3d/ytic),
  2203.                      ytic,
  2204.                      ytic * ceil(y_max3d/ytic),
  2205.                      min_sy_ox);
  2206.          }else{
  2207.             draw_3dytics(ytic * floor(y_max3d/ytic),
  2208.                      ytic,
  2209.                      ytic * ceil(y_min3d/ytic),
  2210.                      min_sy_ox);
  2211.         }
  2212.             break;
  2213.         case TIC_MONTH:
  2214.         draw_month_3dytics(min_sy_ox);
  2215.         break;
  2216.         case TIC_DAY:
  2217.         draw_day_3dytics(min_sy_ox);
  2218.         break;
  2219.         case TIC_SERIES:
  2220.         draw_series_3dytics(yticdef.def.series.start, 
  2221.                     yticdef.def.series.incr, 
  2222.                     yticdef.def.series.end,
  2223.                     min_sy_ox);
  2224.         break;
  2225.         case TIC_USER:
  2226.         draw_set_3dytics(yticdef.def.user,
  2227.                  min_sy_ox);
  2228.         break;
  2229.             default:
  2230.             (*t->text)();
  2231.             (void) fflush(outfile);
  2232.             int_error("unknown tic type in yticdef in do_3dplot", NO_CARET);
  2233.             break;        /* NOTREACHED */
  2234.         }
  2235.     }
  2236. /* label z axis tics */
  2237.     if (ztics && ztic > 0.0 && (draw_surface ||
  2238.                 draw_contour == CONTOUR_SRF ||
  2239.                 draw_contour == CONTOUR_BOTH)) {
  2240.         switch (zticdef.type) {
  2241.             case TIC_COMPUTED:
  2242.          if (min_z < max_z)
  2243.             draw_3dztics(ztic * floor(min_z/ztic),
  2244.                      ztic,
  2245.                      ztic * ceil(max_z/ztic),
  2246.                  min_sx_ox,
  2247.                      min_sx_oy,
  2248.                      min_z,
  2249.                  max_z);
  2250.                 else
  2251.             draw_3dztics(ztic * floor(max_z/ztic),
  2252.                      ztic,
  2253.                      ztic * ceil(min_z/ztic),
  2254.                      min_sx_ox,
  2255.                  min_sx_oy,
  2256.                      max_z,
  2257.                  min_z);
  2258.             break;
  2259.         case TIC_MONTH:
  2260.         draw_month_3dztics(min_sx_ox,min_sx_oy,min_z,max_z);
  2261.         break;
  2262.         case TIC_DAY:
  2263.         draw_day_3dztics(min_sx_ox,min_sx_oy,min_z,max_z);
  2264.         break;
  2265.         case TIC_SERIES:
  2266.         draw_series_3dztics(zticdef.def.series.start, 
  2267.                     zticdef.def.series.incr, 
  2268.                     zticdef.def.series.end,
  2269.                     min_sx_ox,
  2270.                     min_sx_oy,
  2271.                     min_z,
  2272.                     max_z);
  2273.  
  2274.         break;
  2275.         case TIC_USER:
  2276.         draw_set_3dztics(zticdef.def.user,
  2277.                  min_sx_ox,
  2278.                      min_sx_oy,
  2279.                      min_z,
  2280.                  max_z);
  2281.         break;
  2282.             default:
  2283.             (*t->text)();
  2284.             (void) fflush(outfile);
  2285.             int_error("unknown tic type in zticdef in do_3dplot", NO_CARET);
  2286.             break;        /* NOTREACHED */
  2287.         }
  2288.     }
  2289.  
  2290. /* PLACE XLABEL - along the middle grid X axis */
  2291.     if (strlen(xlabel) > 0) {
  2292.        int x1,y1;
  2293.        double step = apx_eq( min_sy_oy, y_min3d ) ?    (y_max3d-y_min3d)/4
  2294.                               : (y_min3d-y_max3d)/4;
  2295.            map3d_xy((x_min3d+x_max3d)/2,min_sy_oy-step, z_min3d,&x1,&y1);
  2296.        x1 += xlabel_xoffset * t->h_char;
  2297.        y1 += xlabel_yoffset * t->v_char;
  2298.        if ((*t->justify_text)(CENTRE))
  2299.         clip_put_text(x1,y1,xlabel);
  2300.        else
  2301.         clip_put_text(x1 - strlen(xlabel)*(t->h_char)/2,y1,xlabel);
  2302.     }
  2303.  
  2304. /* PLACE YLABEL - along the middle grid Y axis */
  2305.     if (strlen(ylabel) > 0) {
  2306.        int x1,y1;
  2307.        double step = apx_eq( min_sy_ox, x_min3d ) ?    (x_max3d-x_min3d)/4
  2308.                               : (x_min3d-x_max3d)/4;
  2309.            map3d_xy(min_sy_ox-step,(y_min3d+y_max3d)/2,z_min3d,&x1,&y1);
  2310.        x1 += ylabel_xoffset * t->h_char;
  2311.        y1 += ylabel_yoffset * t->v_char;
  2312.        if ((*t->justify_text)(CENTRE))
  2313.         clip_put_text(x1,y1,ylabel);
  2314.        else
  2315.         clip_put_text(x1 - strlen(ylabel)*(t->h_char)/2,y1,ylabel);
  2316.     }
  2317.  
  2318. /* PLACE ZLABEL - along the middle grid Z axis */
  2319.     if (strlen(zlabel) > 0 &&
  2320.         (draw_surface ||
  2321.      draw_contour == CONTOUR_SRF ||
  2322.      draw_contour == CONTOUR_BOTH)) {
  2323.            map3d_xy(min_sx_ox,min_sx_oy,max_z + (max_z-min_z)/4, &x, &y);
  2324.  
  2325.        x += zlabel_xoffset * t->h_char;
  2326.        y += zlabel_yoffset * t->v_char;
  2327.        if ((*t->justify_text)(CENTRE))
  2328.         clip_put_text(x,y,zlabel);
  2329.        else
  2330.         clip_put_text(x - strlen(zlabel)*(t->h_char)/2,y,zlabel);
  2331.     }
  2332. }
  2333.  
  2334. /* DRAW_3DXTICS: draw a regular tic series, x axis */
  2335. static draw_3dxtics(start, incr, end, ypos)
  2336.     double start, incr, end, ypos; /* tic series definition */
  2337.         /* assume start < end, incr > 0 */
  2338. {
  2339.     double ticplace;
  2340.     int ltic;        /* for mini log tics */
  2341.     double lticplace;    /* for mini log tics */
  2342.  
  2343.     end = end + SIGNIF*incr; 
  2344.  
  2345.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  2346.         if (ticplace < start || ticplace > end) continue;
  2347.         xtick(ticplace, xformat, incr, 1.0, ypos);
  2348.         if (is_log_x && incr == 1.0) {
  2349.             /* add mini-ticks to log scale ticmarks */
  2350.             for (ltic = 2; ltic < (int)base_log_x; ltic++) {
  2351.                 lticplace = ticplace+log((double)ltic)/log_base_log_x;
  2352.                 xtick(lticplace, "\0", incr, 0.5, ypos);
  2353.             }
  2354.         }
  2355.     }
  2356. }
  2357.  
  2358. /* DRAW_3DYTICS: draw a regular tic series, y axis */
  2359. static draw_3dytics(start, incr, end, xpos)
  2360.     double start, incr, end, xpos; /* tic series definition */
  2361.         /* assume start < end, incr > 0 */
  2362. {
  2363.     double ticplace;
  2364.     int ltic;        /* for mini log tics */
  2365.     double lticplace;    /* for mini log tics */
  2366.  
  2367.     end = end + SIGNIF*incr; 
  2368.  
  2369.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  2370.         if (ticplace < start || ticplace > end) continue;
  2371.         ytick(ticplace, yformat, incr, 1.0, xpos);
  2372.         if (is_log_y && incr == 1.0) {
  2373.             /* add mini-ticks to log scale ticmarks */
  2374.             for (ltic = 2; ltic < (int)base_log_y; ltic++) {
  2375.                 lticplace = ticplace+log((double)ltic)/log_base_log_y;
  2376.                 ytick(lticplace, "\0", incr, 0.5, xpos);
  2377.             }
  2378.         }
  2379.     }
  2380. }
  2381.  
  2382. /* DRAW_3DZTICS: draw a regular tic series, z axis */
  2383. static draw_3dztics(start, incr, end, xpos, ypos, z_min, z_max)
  2384.     double start, incr, end, xpos, ypos, z_min, z_max;
  2385.         /* assume start < end, incr > 0 */
  2386. {
  2387.     int x, y;
  2388.     double ticplace;
  2389.     int ltic;        /* for mini log tics */
  2390.     double lticplace;    /* for mini log tics */
  2391.  
  2392.     end = end + SIGNIF*incr; 
  2393.  
  2394.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  2395.         if (ticplace < start || ticplace > end) continue;
  2396.  
  2397.         ztick(ticplace, zformat, incr, 1.0, xpos, ypos);
  2398.         if (is_log_z && incr == 1.0) {
  2399.             /* add mini-ticks to log scale ticmarks */
  2400.             for (ltic = 2; ltic < (int)base_log_z; ltic++) {
  2401.                 lticplace = ticplace+log((double)ltic)/log_base_log_z;
  2402.                 ztick(lticplace, "\0", incr, 0.5, xpos, ypos);
  2403.             }
  2404.         }
  2405.     }
  2406.  
  2407.     /* Make sure the vertical line is fully drawn. */
  2408.     setlinestyle(-2);    /* axis line type */
  2409.  
  2410.     map3d_xy(xpos, ypos, z_min3d, &x, &y);
  2411.     clip_move(x,y);
  2412.     map3d_xy(xpos, ypos, min(end,z_max)+(is_log_z ? incr : 0.0), &x, &y);
  2413.     clip_vector(x,y);
  2414.  
  2415.     setlinestyle(-1); /* border linetype */
  2416. }
  2417.  
  2418. /* DRAW_SERIES_3DXTICS: draw a user tic series, x axis */
  2419. static draw_series_3dxtics(start, incr, end, ypos)
  2420.         double start, incr, end, ypos; /* tic series definition */
  2421.         /* assume start < end, incr > 0 */
  2422. {
  2423.     double ticplace, place;
  2424.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  2425.     double spacing = is_log_x ? log(incr)/log_base_log_x : incr;
  2426.  
  2427.     if (end == VERYLARGE)
  2428.         end = max(CheckLog(is_log_x, base_log_x, x_min3d),
  2429.               CheckLog(is_log_x, base_log_x, x_max3d));
  2430.     else
  2431.       /* limit to right side of plot */
  2432.       end = min(end, max(CheckLog(is_log_x, base_log_x, x_min3d),
  2433.                  CheckLog(is_log_x, base_log_x, x_max3d)));
  2434.  
  2435.     /* to allow for rounding errors */
  2436.     ticmin = min(x_min3d,x_max3d) - SIGNIF*incr;
  2437.     ticmax = max(x_min3d,x_max3d) + SIGNIF*incr;
  2438.     end = end + SIGNIF*incr; 
  2439.  
  2440.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  2441.         place = (is_log_x ? log(ticplace)/log_base_log_x : ticplace);
  2442.         if ( inrange(place,ticmin,ticmax) )
  2443.          xtick(place, xformat, spacing, 1.0, ypos);
  2444.     }
  2445. }
  2446.  
  2447. /* DRAW_SERIES_3DYTICS: draw a user tic series, y axis */
  2448. static draw_series_3dytics(start, incr, end, xpos)
  2449.         double start, incr, end, xpos; /* tic series definition */
  2450.         /* assume start < end, incr > 0 */
  2451. {
  2452.     double ticplace, place;
  2453.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  2454.     double spacing = is_log_y ? log(incr)/log_base_log_y : incr;
  2455.  
  2456.     if (end == VERYLARGE)
  2457.         end = max(CheckLog(is_log_y, base_log_y, y_min3d),
  2458.               CheckLog(is_log_y, base_log_y, y_max3d));
  2459.     else
  2460.       /* limit to right side of plot */
  2461.       end = min(end, max(CheckLog(is_log_y, base_log_y, y_min3d),
  2462.                  CheckLog(is_log_y, base_log_y, y_max3d)));
  2463.  
  2464.     /* to allow for rounding errors */
  2465.     ticmin = min(y_min3d,y_max3d) - SIGNIF*incr;
  2466.     ticmax = max(y_min3d,y_max3d) + SIGNIF*incr;
  2467.     end = end + SIGNIF*incr; 
  2468.  
  2469.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  2470.         place = (is_log_y ? log(ticplace)/log_base_log_y : ticplace);
  2471.         if ( inrange(place,ticmin,ticmax) )
  2472.          ytick(place, xformat, spacing, 1.0, xpos);
  2473.     }
  2474. }
  2475.  
  2476. /* DRAW_SERIES_3DZTICS: draw a user tic series, z axis */
  2477. static draw_series_3dztics(start, incr, end, xpos, ypos, z_min, z_max)
  2478.         double start, incr, end; /* tic series definition */
  2479.         double xpos, ypos, z_min, z_max;
  2480.         /* assume start < end, incr > 0 */
  2481. {
  2482.     int x, y;
  2483.     double ticplace, place;
  2484.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  2485.     double spacing = is_log_x ? log(incr)/log_base_log_x : incr;
  2486.  
  2487.     if (end == VERYLARGE)
  2488.         end = max(CheckLog(is_log_z, base_log_z, z_min),
  2489.               CheckLog(is_log_z, base_log_z, z_max));
  2490.     else
  2491.       /* limit to right side of plot */
  2492.       end = min(end, max(CheckLog(is_log_z, base_log_z, z_min),
  2493.                  CheckLog(is_log_z, base_log_z, z_max)));
  2494.  
  2495.     /* to allow for rounding errors */
  2496.     ticmin = min(z_min,z_max) - SIGNIF*incr;
  2497.     ticmax = max(z_min,z_max) + SIGNIF*incr;
  2498.     end = end + SIGNIF*incr; 
  2499.  
  2500.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  2501.         place = (is_log_z ? log(ticplace)/log_base_log_z : ticplace);
  2502.         if ( inrange(place,ticmin,ticmax) )
  2503.          ztick(place, zformat, spacing, 1.0, xpos, ypos);
  2504.     }
  2505.  
  2506.     /* Make sure the vertical line is fully drawn. */
  2507.     setlinestyle(-2);    /* axis line type */
  2508.  
  2509.     map3d_xy(xpos, ypos, z_min3d, &x, &y);
  2510.     clip_move(x,y);
  2511.     map3d_xy(xpos, ypos, min(end,z_max)+(is_log_z ? incr : 0.0), &x, &y);
  2512.     clip_vector(x,y);
  2513.  
  2514.     setlinestyle(-1); /* border linetype */
  2515. }
  2516. extern char *month[];
  2517. extern char *day[];
  2518. draw_month_3dxtics(ypos)
  2519. double ypos;
  2520. {
  2521.     long l_ticplace,l_incr,l_end,m_calc;
  2522.  
  2523.     l_ticplace = (long)x_min3d;
  2524.     if((double)l_ticplace<x_min3d)l_ticplace++;
  2525.     l_end=(long)x_max3d;
  2526.     l_incr=(l_end-l_ticplace)/12;
  2527.     if(l_incr<1)l_incr=1;
  2528.     while(l_ticplace<=l_end)
  2529.     {    m_calc=(l_ticplace-1)%12;
  2530.     if(m_calc<0)m_calc += 12;
  2531.     xtick((double)l_ticplace,month[m_calc],(double)l_incr,1.0,ypos);
  2532.     l_ticplace += l_incr;
  2533.     }
  2534. }
  2535. draw_month_3dytics(xpos)
  2536. double xpos;
  2537. {
  2538.     long l_ticplace,l_incr,l_end,m_calc;
  2539.  
  2540.     l_ticplace = (long)y_min3d;
  2541.     if((double)l_ticplace<y_min3d)l_ticplace++;
  2542.     l_end=(long)y_max3d;
  2543.     l_incr=(l_end-l_ticplace)/12;
  2544.     if(l_incr<1)l_incr=1;
  2545.     while(l_ticplace<=l_end)
  2546.     {    m_calc=(l_ticplace-1)%12;
  2547.     if(m_calc<0)m_calc += 12;
  2548.     ytick((double)l_ticplace,month[m_calc],(double)l_incr,1.0,xpos);
  2549.     l_ticplace += l_incr;
  2550.     }
  2551. }
  2552. draw_month_3dztics(xpos,ypos,z_min3d,z_max3d)
  2553. double xpos,ypos,z_min3d,z_max3d;
  2554. {
  2555.     long l_ticplace,l_incr,l_end,m_calc;
  2556.  
  2557.     l_ticplace = (long)z_min3d;
  2558.     if((double)l_ticplace<z_min3d)l_ticplace++;
  2559.     l_end=(long)z_max3d;
  2560.     l_incr=(l_end-l_ticplace)/12;
  2561.     if(l_incr<1)l_incr=1;
  2562.     while(l_ticplace<=l_end)
  2563.     {    m_calc=(l_ticplace-1)%12;
  2564.     if(m_calc<0)m_calc += 12;
  2565.     ztick((double)l_ticplace,month[m_calc],(double)l_incr,1.0,xpos,ypos);
  2566.     l_ticplace += l_incr;
  2567.     }
  2568. }
  2569. draw_day_3dxtics(ypos)
  2570. double ypos;
  2571. {
  2572.     long l_ticplace,l_incr,l_end,m_calc;
  2573.  
  2574.     l_ticplace = (long)x_min3d;
  2575.     if((double)l_ticplace<x_min3d)l_ticplace++;
  2576.     l_end=(long)x_max3d;
  2577.     l_incr=(l_end-l_ticplace)/14;
  2578.     if(l_incr<1)l_incr=1;
  2579.     while(l_ticplace<=l_end)
  2580.     {    m_calc=l_ticplace%7;
  2581.     if(m_calc<0)m_calc += 7;
  2582.     xtick((double)l_ticplace,day[m_calc],(double)l_incr,1.0,ypos);
  2583.     l_ticplace += l_incr;
  2584.     }
  2585. }
  2586. draw_day_3dytics(xpos)
  2587. double xpos;
  2588. {
  2589.     long l_ticplace,l_incr,l_end,m_calc;
  2590.  
  2591.     l_ticplace = (long)y_min3d;
  2592.     if((double)l_ticplace<y_min3d)l_ticplace++;
  2593.     l_end=(long)y_max3d;
  2594.     l_incr=(l_end-l_ticplace)/14;
  2595.     if(l_incr<1)l_incr=1;
  2596.     while(l_ticplace<=l_end)
  2597.     {    m_calc=l_ticplace%7;
  2598.     if(m_calc<0)m_calc += 7;
  2599.     ytick((double)l_ticplace,day[m_calc],(double)l_incr,1.0,xpos);
  2600.     l_ticplace += l_incr;
  2601.     }
  2602. }
  2603. draw_day_3dztics(xpos,ypos,z_min3d,z_max3d)
  2604. double xpos,ypos,z_min3d,z_max3d;
  2605. {
  2606.     long l_ticplace,l_incr,l_end,m_calc;
  2607.  
  2608.     l_ticplace = (long)z_min3d;
  2609.     if((double)l_ticplace<z_min3d)l_ticplace++;
  2610.     l_end=(long)z_max3d;
  2611.     l_incr=(l_end-l_ticplace)/14;
  2612.     if(l_incr<1)l_incr=1;
  2613.     while(l_ticplace<=l_end)
  2614.     {    m_calc=l_ticplace%7;
  2615.     if(m_calc<0)m_calc += 7;
  2616.     ztick((double)l_ticplace,day[m_calc],(double)l_incr,1.0,xpos,ypos);
  2617.     l_ticplace += l_incr;
  2618.     }
  2619. }
  2620. /* DRAW_SET_3DXTICS: draw a user tic set, x axis */
  2621. static draw_set_3dxtics(list, ypos)
  2622.     struct ticmark *list;    /* list of tic marks */
  2623.     double ypos;
  2624. {
  2625.     double ticplace;
  2626.     double incr = (x_max3d - x_min3d) / 10;
  2627.     /* global x_min3d, x_max3d, xscale, y_min3d, y_max3d, yscale */
  2628.  
  2629.     while (list != NULL) {
  2630.        ticplace = (is_log_x ? log(list->position)/log_base_log_x
  2631.                 : list->position);
  2632.        if ( inrange(ticplace, x_min3d, x_max3d)         /* in range */
  2633.           || NearlyEqual(ticplace, x_min3d, incr)    /* == x_min */
  2634.           || NearlyEqual(ticplace, x_max3d, incr))    /* == x_max */
  2635.         xtick(ticplace, list->label, incr, 1.0, ypos);
  2636.  
  2637.        list = list->next;
  2638.     }
  2639. }
  2640.  
  2641. /* DRAW_SET_3DYTICS: draw a user tic set, y axis */
  2642. static draw_set_3dytics(list, xpos)
  2643.     struct ticmark *list;    /* list of tic marks */
  2644.     double xpos;
  2645. {
  2646.     double ticplace;
  2647.     double incr = (y_max3d - y_min3d) / 10;
  2648.     /* global x_min3d, x_max3d, xscale, y_min3d, y_max3d, yscale */
  2649.  
  2650.     while (list != NULL) {
  2651.        ticplace = (is_log_y ? log(list->position)/log_base_log_y
  2652.                 : list->position);
  2653.        if ( inrange(ticplace, y_min3d, y_max3d)           /* in range */
  2654.           || NearlyEqual(ticplace, y_min3d, incr)    /* == y_min3d */
  2655.           || NearlyEqual(ticplace, y_max3d, incr))    /* == y_max3d */
  2656.         ytick(ticplace, list->label, incr, 1.0, xpos);
  2657.  
  2658.        list = list->next;
  2659.     }
  2660. }
  2661.  
  2662. /* DRAW_SET_3DZTICS: draw a user tic set, z axis */
  2663. static draw_set_3dztics(list, xpos, ypos, z_min, z_max)
  2664.     struct ticmark *list;    /* list of tic marks */
  2665.     double xpos, ypos, z_min, z_max;
  2666. {
  2667.     int x, y;
  2668.     double ticplace;
  2669.     double incr = (z_max - z_min) / 10;
  2670.  
  2671.     while (list != NULL) {
  2672.        ticplace = (is_log_z ? log(list->position)/log_base_log_z
  2673.                 : list->position);
  2674.        if ( inrange(ticplace, z_min, z_max)         /* in range */
  2675.           || NearlyEqual(ticplace, z_min, incr)        /* == z_min */
  2676.           || NearlyEqual(ticplace, z_max, incr))    /* == z_max */
  2677.         ztick(ticplace, list->label, incr, 1.0, xpos, ypos);
  2678.  
  2679.        list = list->next;
  2680.     }
  2681.  
  2682.     /* Make sure the vertical line is fully drawn. */
  2683.     setlinestyle(-2);    /* axis line type */
  2684.  
  2685.     map3d_xy(xpos, ypos, z_min, &x, &y);
  2686.     clip_move(x,y);
  2687.     map3d_xy(xpos, ypos, z_max+(is_log_z ? incr : 0.0), &x, &y);
  2688.     clip_vector(x,y);
  2689.  
  2690.     setlinestyle(-1); /* border linetype */
  2691. }
  2692.  
  2693. /* draw and label a x-axis ticmark */
  2694. static xtick(place, text, spacing, ticscale, ypos)
  2695.         double place;                   /* where on axis to put it */
  2696.         char *text;                     /* optional text label */
  2697.         double spacing;         /* something to use with checkzero */
  2698.         double ticscale;         /* scale factor for tic mark (0..1] */
  2699.     double ypos;
  2700. {
  2701.     register struct termentry *t = &term_tbl[term];
  2702.     char ticlabel[101];
  2703.     int x0,y0,x1,y1,x2,y2,x3,y3;
  2704.     int ticsize = (int)((t->h_tic) * ticscale);
  2705.     double v[2], len;
  2706.  
  2707.     place = CheckZero(place,spacing); /* to fix rounding error near zero */
  2708.  
  2709.  
  2710.     if(x_max3d> x_min3d){
  2711.         if (place > x_max3d || place < x_min3d) return(0);
  2712.     }else{
  2713.         if (place > x_min3d || place < x_max3d) return(0);
  2714.     }
  2715.  
  2716.     map3d_xy(place, ypos, z_min3d, &x0, &y0);
  2717.     /* need to figure out which is in. pick the middle point along the */
  2718.     /* axis as in.                               */
  2719.     map3d_xy(place, (y_max3d + y_min3d) / 2, z_min3d, &x1, &y1);
  2720.  
  2721.     /* compute a vector of length 1 into the grid: */
  2722.     v[0] = x1 - x0;
  2723.     v[1] = y1 - y0;
  2724.     len = sqrt(v[0] * v[0] + v[1] * v[1]);
  2725.     if (len == 0.0) return;
  2726.     v[0] /= len;
  2727.     v[1] /= len;
  2728.  
  2729.     if (tic_in) {
  2730.     x1 = x0;
  2731.     y1 = y0;
  2732.     x2 = x1 + ((int) (v[0] * ticsize));
  2733.     y2 = y1 + ((int) (v[1] * ticsize));
  2734.         x3 = x0 - ((int) (v[0] * ticsize * 3)); /* compute text position */
  2735.         y3 = y0 - ((int) (v[1] * ticsize * 3));
  2736.     } else {
  2737.     x1 = x0;
  2738.     y1 = y0;
  2739.     x2 = x0 - ((int) (v[0] * ticsize));
  2740.     y2 = y0 - ((int) (v[1] * ticsize));
  2741.         x3 = x0 - ((int) (v[0] * ticsize * 4)); /* compute text position */
  2742.         y3 = y0 - ((int) (v[1] * ticsize * 4));
  2743.     }
  2744.     clip_move(x1,y1);
  2745.     clip_vector(x2,y2);
  2746.  
  2747.     /* label the ticmark */
  2748.     if (text == NULL)
  2749.      text = xformat;
  2750.  
  2751.     (void) sprintf(ticlabel, text, CheckLog(is_log_x, base_log_x, place));
  2752.     if (apx_eq(v[0], 0.0)) {
  2753.         if ((*t->justify_text)(CENTRE)) {
  2754.             clip_put_text(x3,y3,ticlabel);
  2755.         } else {
  2756.             clip_put_text(x3-(t->h_char)*strlen(ticlabel)/2,y3,ticlabel);
  2757.         }
  2758.     }
  2759.     else if (v[0] > 0) {
  2760.         if ((*t->justify_text)(RIGHT)) {
  2761.             clip_put_text(x3,y3,ticlabel);
  2762.         } else {
  2763.             clip_put_text(x3-(t->h_char)*strlen(ticlabel),y3,ticlabel);
  2764.         }
  2765.     } else {
  2766.         (*t->justify_text)(LEFT);
  2767.     clip_put_text(x3,y3,ticlabel);
  2768.     }
  2769. }
  2770.  
  2771. /* draw and label a y-axis ticmark */
  2772. static ytick(place, text, spacing, ticscale, xpos)
  2773.         double place;                   /* where on axis to put it */
  2774.         char *text;                     /* optional text label */
  2775.         double spacing;         /* something to use with checkzero */
  2776.         double ticscale;         /* scale factor for tic mark (0..1] */
  2777.     double xpos;
  2778. {
  2779.     register struct termentry *t = &term_tbl[term];
  2780.     char ticlabel[101];
  2781.     int x0,y0,x1,y1,x2,y2,x3,y3;
  2782.     int ticsize = (int)((t->h_tic) * ticscale);
  2783.     double v[2], len;
  2784.  
  2785.     place = CheckZero(place,spacing); /* to fix rounding error near zero */
  2786.  
  2787.     if(y_max3d> y_min3d){
  2788.         if (place > y_max3d || place < y_min3d) return(0);
  2789.     }else{
  2790.         if (place > y_min3d || place < y_max3d) return(0);
  2791.     }
  2792.  
  2793.     map3d_xy(xpos, place, z_min3d, &x0, &y0);
  2794.     /* need to figure out which is in. pick the middle point along the */
  2795.     /* axis as in.                               */
  2796.     map3d_xy((x_max3d + x_min3d) / 2, place, z_min3d, &x1, &y1);
  2797.  
  2798.     /* compute a vector of length 1 into the grid: */
  2799.     v[0] = x1 - x0;
  2800.     v[1] = y1 - y0;
  2801.     len = sqrt(v[0] * v[0] + v[1] * v[1]);
  2802.     if (len == 0.0) return(0);
  2803.     v[0] /= len;
  2804.     v[1] /= len;
  2805.  
  2806.     if (tic_in) {
  2807.     x1 = x0;
  2808.     y1 = y0;
  2809.     x2 = x1 + ((int) (v[0] * ticsize));
  2810.     y2 = y1 + ((int) (v[1] * ticsize));
  2811.         x3 = x0 - ((int) (v[0] * ticsize * 3)); /* compute text position */
  2812.         y3 = y0 - ((int) (v[1] * ticsize * 3));
  2813.     } else {
  2814.     x1 = x0;
  2815.     y1 = y0;
  2816.     x2 = x0 - ((int) (v[0] * ticsize));
  2817.     y2 = y0 - ((int) (v[1] * ticsize));
  2818.         x3 = x0 - ((int) (v[0] * ticsize * 4)); /* compute text position */
  2819.         y3 = y0 - ((int) (v[1] * ticsize * 4));
  2820.     }
  2821.     clip_move(x1,y1);
  2822.     clip_vector(x2,y2);
  2823.  
  2824.     /* label the ticmark */
  2825.     if (text == NULL)
  2826.      text = yformat;
  2827.  
  2828.     (void) sprintf(ticlabel, text, CheckLog(is_log_y, base_log_y, place));
  2829.     if (apx_eq(v[0], 0.0)) {
  2830.         if ((*t->justify_text)(CENTRE)) {
  2831.             clip_put_text(x3,y3,ticlabel);
  2832.         } else {
  2833.             clip_put_text(x3-(t->h_char)*strlen(ticlabel)/2,y3,ticlabel);
  2834.         }
  2835.     }
  2836.     else if (v[0] > 0) {
  2837.         if ((*t->justify_text)(RIGHT)) {
  2838.             clip_put_text(x3,y3,ticlabel);
  2839.         } else {
  2840.             clip_put_text(x3-(t->h_char)*strlen(ticlabel),y3,ticlabel);
  2841.         }
  2842.     } else {
  2843.         (*t->justify_text)(LEFT);
  2844.     clip_put_text(x3,y3,ticlabel);
  2845.     }
  2846. }
  2847.  
  2848. /* draw and label a z-axis ticmark */
  2849. static ztick(place, text, spacing, ticscale, xpos, ypos)
  2850.         double place;                   /* where on axis to put it */
  2851.         char *text;                     /* optional text label */
  2852.         double spacing;         /* something to use with checkzero */
  2853.         double ticscale;         /* scale factor for tic mark (0..1] */
  2854.     double xpos, ypos;
  2855. {
  2856.     register struct termentry *t = &term_tbl[term];
  2857.     char ticlabel[101];
  2858.     int x0,y0,x1,y1,x2,y2,x3,y3;
  2859.     int ticsize = (int)((t->h_tic) * ticscale);
  2860.  
  2861.     place = CheckZero(place,spacing); /* to fix rounding error near zero */
  2862.  
  2863.     map3d_xy(xpos, ypos, place, &x0, &y0);
  2864.  
  2865.     if (tic_in) {
  2866.     x1 = x0;
  2867.     y1 = y0;
  2868.     x2 = x0 + ticsize;
  2869.     y2 = y0;
  2870.         x3 = x0 - ticsize;
  2871.         y3 = y0;
  2872.     } else {
  2873.     x1 = x0;
  2874.     y1 = y0;
  2875.     x2 = x0 - ticsize;
  2876.     y2 = y0;
  2877.         x3 = x0 - ticsize * 2; /* compute text position */
  2878.         y3 = y0;
  2879.     }
  2880.     clip_move(x1,y1);
  2881.     clip_vector(x2,y2);
  2882.  
  2883.     /* label the ticmark */
  2884.     if (text == NULL)
  2885.      text = zformat;
  2886.  
  2887.     (void) sprintf(ticlabel, text, CheckLog(is_log_z, base_log_z, place));
  2888.     if ((*t->justify_text)(RIGHT)) {
  2889.         clip_put_text(x3,y3,ticlabel);
  2890.     } else {
  2891.         clip_put_text(x3-(t->h_char)*(strlen(ticlabel)+1),y3,ticlabel);
  2892.     }
  2893. }
  2894.